Why is constness not enforced for pointers?
up vote
24
down vote
favorite
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
add a comment |
up vote
24
down vote
favorite
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
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
add a comment |
up vote
24
down vote
favorite
up vote
24
down vote
favorite
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
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
c++ pointers const transitive-const
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
add a comment |
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
add a comment |
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.
2
I often find that tools like cdecl.org are useful for making sure that I'm reading theconstthe 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 withusingnottypedef!). For simple cases like this you should be able to read it instinctively. Remember,constapplies 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
add a comment |
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
}
};
add a comment |
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.
2
I often find that tools like cdecl.org are useful for making sure that I'm reading theconstthe 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 withusingnottypedef!). For simple cases like this you should be able to read it instinctively. Remember,constapplies 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
add a comment |
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.
2
I often find that tools like cdecl.org are useful for making sure that I'm reading theconstthe 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 withusingnottypedef!). For simple cases like this you should be able to read it instinctively. Remember,constapplies 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
add a comment |
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.
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.
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 theconstthe 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 withusingnottypedef!). For simple cases like this you should be able to read it instinctively. Remember,constapplies 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
add a comment |
2
I often find that tools like cdecl.org are useful for making sure that I'm reading theconstthe 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 withusingnottypedef!). For simple cases like this you should be able to read it instinctively. Remember,constapplies 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
add a comment |
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
}
};
add a comment |
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
}
};
add a comment |
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
}
};
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
}
};
edited Oct 29 at 22:07
answered Oct 2 at 11:48
bolov
30.1k668128
30.1k668128
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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