{"id":1184,"date":"2013-08-05T01:00:00","date_gmt":"2013-08-04T23:00:00","guid":{"rendered":"https:\/\/www.fussylogic.co.uk\/blog\/?p=1184"},"modified":"2013-08-09T15:04:07","modified_gmt":"2013-08-09T14:04:07","slug":"pointer-implications-c-2","status":"publish","type":"post","link":"https:\/\/www.fussylogic.co.uk\/blog\/?p=1184","title":{"rendered":"Pointer Implications (C)"},"content":{"rendered":"<p>Consider the declarations of various pointer-to-an-O-accepting functions:<\/p>\n<ul>\n<li><code>f( O * )<\/code><\/li>\n<li><code>f( const O * )<\/code><\/li>\n<li><code>f( O * const )<\/code><\/li>\n<li><code>f( const O * const )<\/code><\/li>\n<\/ul>\n<p>What is the author of <code>f()<\/code> telling us about what the function will do with the <code>O<\/code> we reference in each of these cases? This, and subsequent articles, will discuss why you would choose between these various argument types. Essentially we\u00e2\u20ac\u2122re talking about what you are implying to the caller of your function when you pick a particular pointer declaration.<\/p>\n<h2 id=\"fo\"><code>f(O*)<\/code><\/h2>\n<p>We\u00e2\u20ac\u2122re passing a pointer by value, it\u00e2\u20ac\u2122s so common that it\u00e2\u20ac\u2122s easy to forget that passing a pointer, while it\u00e2\u20ac\u2122s a pass-by-reference to the pointed to object, is <em>still<\/em> pass by value as far as the parameter is concerned. It should be obvious that this does nothing:<\/p>\n<pre class=\"sourceCode C\"><code class=\"sourceCode c\">    <span class=\"dt\">void<\/span> f(O* p) {\n        p = nullptr;\n    }<\/code><\/pre>\n<p><code>p<\/code> has been passed-by-value, so is just another local variable. <code>*p<\/code> on the other hand is a reference to some external object and we certainly can modify that inside <code>f()<\/code>.<\/p>\n<pre class=\"sourceCode C\"><code class=\"sourceCode c\">    <span class=\"dt\">void<\/span> f(O* p) {\n        <span class=\"kw\">if<\/span>(p == nullptr)\n            <span class=\"kw\">return<\/span>;\n        p-&gt;modify();\n    }<\/code><\/pre>\n<p>The above is, fundamentally, what the function declaration <code>f(O*)<\/code> says about <code>f()<\/code> \u00e2\u20ac\u201c it will modify the object given to it, and the object need not exist (passing a pointer means you have to allow that the pointer points at nothing, null). There is, unfortunately, nothing to stop <code>f()<\/code> modifying not just the content, but the lifetime of <code>O<\/code>.<\/p>\n<pre class=\"sourceCode C\"><code class=\"sourceCode c\">    <span class=\"dt\">void<\/span> f(O* p) {\n        delete p;\n        <span class=\"co\">\/\/ The following has no effect, we&#39;ve established that the<\/span>\n        <span class=\"co\">\/\/ p has been passed by value<\/span>\n        p = nullptr;\n    }\n\n    <span class=\"co\">\/\/ ... elsewhere in the forest ...<\/span>\n    myObject = new O;\n    f( myObject );\n    <span class=\"co\">\/\/ f() has destroyed myObject, so we have to remember to do this<\/span>\n    myObject = nullptr;\n    <span class=\"co\">\/\/ ... if we forget then when we try this, we could be hiding a<\/span>\n    <span class=\"co\">\/\/ disaster for later.<\/span>\n    myObject-&gt;modify();<\/code><\/pre>\n<p>We\u00e2\u20ac\u2122ll come to the correct way to modify an object lifetime within a function later. For now, here\u00e2\u20ac\u2122s a rule: <em>never<\/em> delete an object via a raw pointer passed-by-value to a function. Let\u00e2\u20ac\u2122s look at why:<\/p>\n<pre class=\"sourceCode C\"><code class=\"sourceCode c\">    <span class=\"dt\">void<\/span> f(O* p) {\n        delete p;\n        <span class=\"co\">\/\/ The following has no effect, we&#39;ve established that the<\/span>\n        <span class=\"co\">\/\/ p has been passed by value<\/span>\n        p = nullptr;\n    }\n\n    <span class=\"co\">\/\/ ... elsewhere in the forest ...<\/span>\n    O myObject;\n    <span class=\"co\">\/\/ This will go very, very badly, as f() assumes that the passed<\/span>\n    <span class=\"co\">\/\/ object is allocated on the free-store.  It isn&#39;t.<\/span>\n    f( &amp;myObject );<\/code><\/pre>\n<p>By using <code>delete<\/code> in a function, we\u00e2\u20ac\u2122ve forced all objects of that type to be allocated on the free-store; and we\u00e2\u20ac\u2122ve forced the caller to come and read our API in order to know that fact. We should, as far as possible, not inform of limitations by comment. We should limit by language, and let the compiler give errors when those limits aren\u00e2\u20ac\u2122t obeyed. Unfortunately, C offers no such facility.<\/p>\n<h2 id=\"fconst-o\"><code>f(const O*)<\/code><\/h2>\n<p>One standard limit, is that of <code>const<\/code>. Here we are telling the caller that <code>f()<\/code> will not modify the pointed-to object, and that the object is allowed not to exist. The compiler will warn us if we try to use any non-const member function of <code>O<\/code>.<\/p>\n<pre class=\"sourceCode C\"><code class=\"sourceCode c\">    <span class=\"dt\">int<\/span> f(<span class=\"dt\">const<\/span> O* p) {\n        <span class=\"kw\">if<\/span>(p == nullptr)\n            <span class=\"kw\">return<\/span> DEFAULT;\n        <span class=\"kw\">return<\/span> p-&gt;query();\n    }<\/code><\/pre>\n<p>A function that takes a <code>const O*<\/code> would be pointless if it didn\u00e2\u20ac\u2122t return something. Since <code>const O*<\/code> can\u00e2\u20ac\u2122t be modified, if <code>f()<\/code> doesn\u00e2\u20ac\u2122t return something, then it would have zero effect. Here we\u00e2\u20ac\u2122re using <code>f()<\/code> as a null-safe wrapper around an <code>O<\/code>.<\/p>\n<p>We needn\u00e2\u20ac\u2122t worry about lifetime in this case, <code>delete<\/code> requires a non-const pointer, so the compiler will not let us call <code>delete p<\/code> here.<\/p>\n<p>It\u00e2\u20ac\u2122s important to remember what <code>const O*<\/code> means \u00e2\u20ac\u201c that the <em>pointed-to<\/em> object cannot be modified. The pointer itself <em>can<\/em> be modified. As in the previous section though, it would serve no purpose. However, the compiler will not stop you.<\/p>\n<pre class=\"sourceCode C\"><code class=\"sourceCode c\">    <span class=\"dt\">int<\/span> f(<span class=\"dt\">const<\/span> O* p) {\n        <span class=\"kw\">if<\/span>(p == nullptr)\n            <span class=\"kw\">return<\/span> DEFAULT;\n        <span class=\"dt\">int<\/span> ret = p-&gt;query();\n        p = nullptr;\n        <span class=\"kw\">return<\/span> ret;\n    }<\/code><\/pre>\n<h2 id=\"fo-const-and-fconst-o-const\"><code>f(O * const)<\/code> and <code>f(const O * const)<\/code><\/h2>\n<p>I\u00e2\u20ac\u2122ve included this one for completeness; but you will never see it. This is a nonsense declaration. <code>O * const<\/code> is our way of telling the compiler that the <em>pointer<\/em> is itself <code>const<\/code> and cannot be modified. The thing pointed to is fair game. Still remembering that the pointer is passed by value, we are talking only about the function-scoped copy of the pointer that can\u00e2\u20ac\u2122t be modified. We\u00e2\u20ac\u2122ve already seen that modifying the pointer within the function does absolutely nothing, so why would it matter to the caller that we\u00e2\u20ac\u2122ve told the compiler to prevent us from doing that? From the perspective of the caller these two declarations are identical:<\/p>\n<ul>\n<li><code>f( O * )<\/code><\/li>\n<li><code>f( O * const )<\/code><\/li>\n<\/ul>\n<p>The caller doesn\u00e2\u20ac\u2122t care whether the function modifies it\u00e2\u20ac\u2122s local copy of the pointer or not, it only cares that <code>f()<\/code> can modify the pointed-to object, which in both these cases it can.<\/p>\n<p>By extension then, the following two declarations are identical from the point of view of the caller.<\/p>\n<ul>\n<li><code>f( const O * )<\/code><\/li>\n<li><code>f( const O * const )<\/code><\/li>\n<\/ul>\n<p>The caller knows that neither modifies the pointed-to-object.<\/p>\n<hr \/>\n<p>Next time, C++.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Consider the declarations of various pointer-to-an-O-accepting functions: f( O * ) f( const O * ) f( O * const ) f( const O * const ) What is the author of f() telling us about what the function will do with the O we reference in each of these cases? This, and subsequent articles,\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.fussylogic.co.uk\/blog\/?p=1184\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[65,42,6],"_links":{"self":[{"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1184"}],"collection":[{"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1184"}],"version-history":[{"count":3,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1184\/revisions"}],"predecessor-version":[{"id":1195,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1184\/revisions\/1195"}],"wp:attachment":[{"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1184"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1184"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1184"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}