Why is constness not enforced for pointers?











up vote
24
down vote

favorite
3












Consider the following code snippet:



class A
{
public:

void nonConstFun()
{

}
};

class B
{
private:

A a_;
A * pA_;

public:

void fun() const
{
pA_->nonConstFun();
//a_.nonConstFun(); // Gives const related error
}
};

int main()
{
B b;
b.fun();
}


Here I am expecting the compiler to fail the compilation for lack of constness for calling A::nonConstFun() inside B::fun() irrespective of the type of A object.



However the compiler complains for the object, but not for the pointer. Why?
I am using VS2017 on Windows 10.










share|improve this question
























  • a const member function means it will not change the internal state of this object, while what the object has a reference to might be changed.
    – John Z. Li
    Oct 8 at 9:13















up vote
24
down vote

favorite
3












Consider the following code snippet:



class A
{
public:

void nonConstFun()
{

}
};

class B
{
private:

A a_;
A * pA_;

public:

void fun() const
{
pA_->nonConstFun();
//a_.nonConstFun(); // Gives const related error
}
};

int main()
{
B b;
b.fun();
}


Here I am expecting the compiler to fail the compilation for lack of constness for calling A::nonConstFun() inside B::fun() irrespective of the type of A object.



However the compiler complains for the object, but not for the pointer. Why?
I am using VS2017 on Windows 10.










share|improve this question
























  • a const member function means it will not change the internal state of this object, while what the object has a reference to might be changed.
    – John Z. Li
    Oct 8 at 9:13













up vote
24
down vote

favorite
3









up vote
24
down vote

favorite
3






3





Consider the following code snippet:



class A
{
public:

void nonConstFun()
{

}
};

class B
{
private:

A a_;
A * pA_;

public:

void fun() const
{
pA_->nonConstFun();
//a_.nonConstFun(); // Gives const related error
}
};

int main()
{
B b;
b.fun();
}


Here I am expecting the compiler to fail the compilation for lack of constness for calling A::nonConstFun() inside B::fun() irrespective of the type of A object.



However the compiler complains for the object, but not for the pointer. Why?
I am using VS2017 on Windows 10.










share|improve this question















Consider the following code snippet:



class A
{
public:

void nonConstFun()
{

}
};

class B
{
private:

A a_;
A * pA_;

public:

void fun() const
{
pA_->nonConstFun();
//a_.nonConstFun(); // Gives const related error
}
};

int main()
{
B b;
b.fun();
}


Here I am expecting the compiler to fail the compilation for lack of constness for calling A::nonConstFun() inside B::fun() irrespective of the type of A object.



However the compiler complains for the object, but not for the pointer. Why?
I am using VS2017 on Windows 10.







c++ pointers const transitive-const






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 2 at 19:37









Deduplicator

33.9k64787




33.9k64787










asked Oct 2 at 11:39









Arun Valakottial

1,26621632




1,26621632












  • a const member function means it will not change the internal state of this object, while what the object has a reference to might be changed.
    – John Z. Li
    Oct 8 at 9:13


















  • a const member function means it will not change the internal state of this object, while what the object has a reference to might be changed.
    – John Z. Li
    Oct 8 at 9:13
















a const member function means it will not change the internal state of this object, while what the object has a reference to might be changed.
– John Z. Li
Oct 8 at 9:13




a const member function means it will not change the internal state of this object, while what the object has a reference to might be changed.
– John Z. Li
Oct 8 at 9:13












2 Answers
2






active

oldest

votes

















up vote
43
down vote



accepted










It is enforced.



If you try changing the pointer, the compiler will not let you.



The thing that the pointer points to, however, is a different conversation.



Remember, T* const and T const* are not the same thing!



You can protect that by either actually making it A const*, or simply by writing your function in the manner that is appropriate.






share|improve this answer

















  • 2




    I often find that tools like cdecl.org are useful for making sure that I'm reading the const the same way that the compiler is reading it.
    – bta
    Oct 2 at 22:44












  • @bta For more complex types that is certainly helpful, although generally you want to avoid those types or at least spell them in a modern & clear way (make aliases, and do it with using not typedef!). For simple cases like this you should be able to read it instinctively. Remember, const applies to the left, unless there's nothing there in which case it applies to the right.
    – Lightness Races in Orbit
    Oct 3 at 13:10


















up vote
51
down vote













The other answers explain the T* const vs T const * which is what is happening. But it important to understand the implication of this beyond just the mere syntax.



When you have a T* inside a structure the pointer is inside the object, but the pointed object is physically outside of the struct. That is why for a const object with a T* member it is not allowed to modify the pointer, but it is allowed to modify the pointed object - because physically the pointed object is outside the enclosing object.



And it is up to the programmer to decide if the pointed object is logically part of the enclosing object (and as such should share constness with the enclosing) or if it is logically an external entity.



The shortcoming of C++ is that it doesn't offer an easy way to express a logical constness as stated above (what you actually expected from your code).



This is known and for this exact purpose there is an experimental class which is not yet standard propagate_const




std::experimental::propagate_const is a const-propagating wrapper for
pointers and pointer-like objects. It treats the wrapped pointer as a
pointer to const when accessed through a const access path, hence the
name.




struct B
{
A a_;
std::experimental::propagate_const<A *> pA_;

void fun()
{
pA_->nonConstFun(); // OK
}
void fun() const
{
// pA_->nonConstFun(); // compilation error
}
};





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52607625%2fwhy-is-constness-not-enforced-for-pointers%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    43
    down vote



    accepted










    It is enforced.



    If you try changing the pointer, the compiler will not let you.



    The thing that the pointer points to, however, is a different conversation.



    Remember, T* const and T const* are not the same thing!



    You can protect that by either actually making it A const*, or simply by writing your function in the manner that is appropriate.






    share|improve this answer

















    • 2




      I often find that tools like cdecl.org are useful for making sure that I'm reading the const the same way that the compiler is reading it.
      – bta
      Oct 2 at 22:44












    • @bta For more complex types that is certainly helpful, although generally you want to avoid those types or at least spell them in a modern & clear way (make aliases, and do it with using not typedef!). For simple cases like this you should be able to read it instinctively. Remember, const applies to the left, unless there's nothing there in which case it applies to the right.
      – Lightness Races in Orbit
      Oct 3 at 13:10















    up vote
    43
    down vote



    accepted










    It is enforced.



    If you try changing the pointer, the compiler will not let you.



    The thing that the pointer points to, however, is a different conversation.



    Remember, T* const and T const* are not the same thing!



    You can protect that by either actually making it A const*, or simply by writing your function in the manner that is appropriate.






    share|improve this answer

















    • 2




      I often find that tools like cdecl.org are useful for making sure that I'm reading the const the same way that the compiler is reading it.
      – bta
      Oct 2 at 22:44












    • @bta For more complex types that is certainly helpful, although generally you want to avoid those types or at least spell them in a modern & clear way (make aliases, and do it with using not typedef!). For simple cases like this you should be able to read it instinctively. Remember, const applies to the left, unless there's nothing there in which case it applies to the right.
      – Lightness Races in Orbit
      Oct 3 at 13:10













    up vote
    43
    down vote



    accepted







    up vote
    43
    down vote



    accepted






    It is enforced.



    If you try changing the pointer, the compiler will not let you.



    The thing that the pointer points to, however, is a different conversation.



    Remember, T* const and T const* are not the same thing!



    You can protect that by either actually making it A const*, or simply by writing your function in the manner that is appropriate.






    share|improve this answer












    It is enforced.



    If you try changing the pointer, the compiler will not let you.



    The thing that the pointer points to, however, is a different conversation.



    Remember, T* const and T const* are not the same thing!



    You can protect that by either actually making it A const*, or simply by writing your function in the manner that is appropriate.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Oct 2 at 11:45









    Lightness Races in Orbit

    279k51450765




    279k51450765








    • 2




      I often find that tools like cdecl.org are useful for making sure that I'm reading the const the same way that the compiler is reading it.
      – bta
      Oct 2 at 22:44












    • @bta For more complex types that is certainly helpful, although generally you want to avoid those types or at least spell them in a modern & clear way (make aliases, and do it with using not typedef!). For simple cases like this you should be able to read it instinctively. Remember, const applies to the left, unless there's nothing there in which case it applies to the right.
      – Lightness Races in Orbit
      Oct 3 at 13:10














    • 2




      I often find that tools like cdecl.org are useful for making sure that I'm reading the const the same way that the compiler is reading it.
      – bta
      Oct 2 at 22:44












    • @bta For more complex types that is certainly helpful, although generally you want to avoid those types or at least spell them in a modern & clear way (make aliases, and do it with using not typedef!). For simple cases like this you should be able to read it instinctively. Remember, const applies to the left, unless there's nothing there in which case it applies to the right.
      – Lightness Races in Orbit
      Oct 3 at 13:10








    2




    2




    I often find that tools like cdecl.org are useful for making sure that I'm reading the const the same way that the compiler is reading it.
    – bta
    Oct 2 at 22:44






    I often find that tools like cdecl.org are useful for making sure that I'm reading the const the same way that the compiler is reading it.
    – bta
    Oct 2 at 22:44














    @bta For more complex types that is certainly helpful, although generally you want to avoid those types or at least spell them in a modern & clear way (make aliases, and do it with using not typedef!). For simple cases like this you should be able to read it instinctively. Remember, const applies to the left, unless there's nothing there in which case it applies to the right.
    – Lightness Races in Orbit
    Oct 3 at 13:10




    @bta For more complex types that is certainly helpful, although generally you want to avoid those types or at least spell them in a modern & clear way (make aliases, and do it with using not typedef!). For simple cases like this you should be able to read it instinctively. Remember, const applies to the left, unless there's nothing there in which case it applies to the right.
    – Lightness Races in Orbit
    Oct 3 at 13:10












    up vote
    51
    down vote













    The other answers explain the T* const vs T const * which is what is happening. But it important to understand the implication of this beyond just the mere syntax.



    When you have a T* inside a structure the pointer is inside the object, but the pointed object is physically outside of the struct. That is why for a const object with a T* member it is not allowed to modify the pointer, but it is allowed to modify the pointed object - because physically the pointed object is outside the enclosing object.



    And it is up to the programmer to decide if the pointed object is logically part of the enclosing object (and as such should share constness with the enclosing) or if it is logically an external entity.



    The shortcoming of C++ is that it doesn't offer an easy way to express a logical constness as stated above (what you actually expected from your code).



    This is known and for this exact purpose there is an experimental class which is not yet standard propagate_const




    std::experimental::propagate_const is a const-propagating wrapper for
    pointers and pointer-like objects. It treats the wrapped pointer as a
    pointer to const when accessed through a const access path, hence the
    name.




    struct B
    {
    A a_;
    std::experimental::propagate_const<A *> pA_;

    void fun()
    {
    pA_->nonConstFun(); // OK
    }
    void fun() const
    {
    // pA_->nonConstFun(); // compilation error
    }
    };





    share|improve this answer



























      up vote
      51
      down vote













      The other answers explain the T* const vs T const * which is what is happening. But it important to understand the implication of this beyond just the mere syntax.



      When you have a T* inside a structure the pointer is inside the object, but the pointed object is physically outside of the struct. That is why for a const object with a T* member it is not allowed to modify the pointer, but it is allowed to modify the pointed object - because physically the pointed object is outside the enclosing object.



      And it is up to the programmer to decide if the pointed object is logically part of the enclosing object (and as such should share constness with the enclosing) or if it is logically an external entity.



      The shortcoming of C++ is that it doesn't offer an easy way to express a logical constness as stated above (what you actually expected from your code).



      This is known and for this exact purpose there is an experimental class which is not yet standard propagate_const




      std::experimental::propagate_const is a const-propagating wrapper for
      pointers and pointer-like objects. It treats the wrapped pointer as a
      pointer to const when accessed through a const access path, hence the
      name.




      struct B
      {
      A a_;
      std::experimental::propagate_const<A *> pA_;

      void fun()
      {
      pA_->nonConstFun(); // OK
      }
      void fun() const
      {
      // pA_->nonConstFun(); // compilation error
      }
      };





      share|improve this answer

























        up vote
        51
        down vote










        up vote
        51
        down vote









        The other answers explain the T* const vs T const * which is what is happening. But it important to understand the implication of this beyond just the mere syntax.



        When you have a T* inside a structure the pointer is inside the object, but the pointed object is physically outside of the struct. That is why for a const object with a T* member it is not allowed to modify the pointer, but it is allowed to modify the pointed object - because physically the pointed object is outside the enclosing object.



        And it is up to the programmer to decide if the pointed object is logically part of the enclosing object (and as such should share constness with the enclosing) or if it is logically an external entity.



        The shortcoming of C++ is that it doesn't offer an easy way to express a logical constness as stated above (what you actually expected from your code).



        This is known and for this exact purpose there is an experimental class which is not yet standard propagate_const




        std::experimental::propagate_const is a const-propagating wrapper for
        pointers and pointer-like objects. It treats the wrapped pointer as a
        pointer to const when accessed through a const access path, hence the
        name.




        struct B
        {
        A a_;
        std::experimental::propagate_const<A *> pA_;

        void fun()
        {
        pA_->nonConstFun(); // OK
        }
        void fun() const
        {
        // pA_->nonConstFun(); // compilation error
        }
        };





        share|improve this answer














        The other answers explain the T* const vs T const * which is what is happening. But it important to understand the implication of this beyond just the mere syntax.



        When you have a T* inside a structure the pointer is inside the object, but the pointed object is physically outside of the struct. That is why for a const object with a T* member it is not allowed to modify the pointer, but it is allowed to modify the pointed object - because physically the pointed object is outside the enclosing object.



        And it is up to the programmer to decide if the pointed object is logically part of the enclosing object (and as such should share constness with the enclosing) or if it is logically an external entity.



        The shortcoming of C++ is that it doesn't offer an easy way to express a logical constness as stated above (what you actually expected from your code).



        This is known and for this exact purpose there is an experimental class which is not yet standard propagate_const




        std::experimental::propagate_const is a const-propagating wrapper for
        pointers and pointer-like objects. It treats the wrapped pointer as a
        pointer to const when accessed through a const access path, hence the
        name.




        struct B
        {
        A a_;
        std::experimental::propagate_const<A *> pA_;

        void fun()
        {
        pA_->nonConstFun(); // OK
        }
        void fun() const
        {
        // pA_->nonConstFun(); // compilation error
        }
        };






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Oct 29 at 22:07

























        answered Oct 2 at 11:48









        bolov

        30.1k668128




        30.1k668128






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52607625%2fwhy-is-constness-not-enforced-for-pointers%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Landwehr

            Reims

            Javascript gets undefined on array