Reputation: 27350
I'm struggling a bit trying to work out how to pass const pointers to classes around using shared pointers. Normally you just declare a pointer to an object const
and you can no longer change any members in it, however if the class is using shared pointers the const
does not seem to apply.
Here is a compilable example of the problem. In processA()
, it should not be possible to add another element to the vector as the object is supposed to be const
.
What am I doing wrong?
#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>
struct C {
int value;
};
struct B {
std::vector<C> vectorOfC;
};
struct A {
boost::shared_ptr<B> b;
};
typedef boost::shared_ptr<A> PtrA;
void processA(boost::shared_ptr<const A> a)
{
// This should not be possible because 'a' points to const
C c2;
c2.value = 456;
a->b->vectorOfC.push_back(c2);
for (std::vector<C>::const_iterator
i = a->b->vectorOfC.begin(); i != a->b->vectorOfC.end(); i++
) {
std::cout << i->value << std::endl;
}
}
int main(void)
{
C c;
c.value = 123;
PtrA a(new A);
a->b.reset(new B);
a->b->vectorOfC.push_back(c);
processA(a);
return 0;
}
Upvotes: 1
Views: 566
Reputation: 145457
All this stuff about shared_ptr
is just a red herring.
You have pointer to a const
object that has a pointer to a non-const
object.
You can of course modify the latter object.
Upvotes: 3
Reputation: 6578
I think you're misunderstanding how const
works with pointers.
const T *
doesn't declare a const
pointer, it declares a pointer to const
. I.e. the pointer is mutable, but the thing(s) it points at are not.
When you add const
to a pointer, you actually get T * const
, which is a const
pointer to mutable object(s), i.e. you can still change the pointee through the pointer.
In the case of std::shared_ptr
(or boost::shared_ptr
) adding const
leaves you with const std::shared_ptr<T>
, i.e. you cannot change the shared_ptr
, but you can change the pointee, because the shared_ptr
does not point to an immutable object.
To rectify this, you want to use std::shared_ptr<const T>
, which is a mutable shared_ptr
to a const
object.
You can get around this by:
boost::shared_ptr
s pointers to const
, or, if in certain instances it's acceptable to mutate the pointeeconst
, the other being mutable) to properly return boost::shared_ptr<const T>
in the proper case, or, if callers don't actually need the boost::shared_ptr
itselfconst
, the other being mutable) to return references to T
, with the const
overload returning const T &
and the mutable overload returning T &
Upvotes: 2