Difference between `const shared_ptr<T>` and `shared_ptr<const T>`? - c++

I'm writing an accessor method for a shared pointer in C++ that goes something like this:
class Foo {
public:
return_type getBar() const {
return m_bar;
}
private:
boost::shared_ptr<Bar> m_bar;
}
So to support the const-ness of getBar() the return type should be a boost::shared_ptr that prevents modification of the Bar it points to. My guess is that shared_ptr<const Bar> is the type I want to return to do that, whereas const shared_ptr<Bar> would prevent reassignment of the pointer itself to point to a different Bar but allow modification of the Bar that it points to... However, I'm not sure. I'd appreciate it if someone who knows for sure could either confirm this, or correct me if I got it wrong. Thanks!

You are right. shared_ptr<const T> p; is similar to const T * p; (or, equivalently, T const * p;), that is, the pointed object is const whereas const shared_ptr<T> p; is similar to T* const p; which means that p is const. In summary:
shared_ptr<T> p; ---> T * p; : nothing is const
const shared_ptr<T> p; ---> T * const p; : p is const
shared_ptr<const T> p; ---> const T * p; <=> T const * p; : *p is const
const shared_ptr<const T> p; ---> const T * const p; <=> T const * const p; : p and *p are const.
The same holds for weak_ptr and unique_ptr.

I would like to a simple demostration based on #Cassio Neri's answer:
#include <memory>
int main(){
std::shared_ptr<int> i = std::make_shared<int>(1);
std::shared_ptr<int const> ci;
// i = ci; // compile error
ci = i;
std::cout << *i << "\t" << *ci << std::endl; // both will be 1
*i = 2;
std::cout << *i << "\t" << *ci << std::endl; // both will be 2
i = std::make_shared<int>(3);
std::cout << *i << "\t" << *ci << std::endl; // only *i has changed
// *ci = 20; // compile error
ci = std::make_shared<int>(5);
std::cout << *i << "\t" << *ci << std::endl; // only *ci has changed
}

boost::shared_ptr<Bar const> prevents modification of the
Bar object through the shared pointer. As a return value, the
const in boost::shared_ptr<Bar> const means that you cannot
call a non-const function on the returned temporary; if it were
for a real pointer (e.g. Bar* const), it would be completely
ignored.
In general, even here, the usual rules apply: const modifies
what precedes it: in boost::shared_ptr<Bar const>, the Bar;
in boost::shared_ptr<Bar> const, it's the instantiation (the
expression boost::shared_ptr<Bar> which is const.

#Check this simple code to understand... copy-paste the below code to check on any c++11 compiler
#include <memory>
using namespace std;
class A {
public:
int a = 5;
};
shared_ptr<A> f1() {
const shared_ptr<A> sA(new A);
shared_ptr<A> sA2(new A);
sA = sA2; // compile-error
return sA;
}
shared_ptr<A> f2() {
shared_ptr<const A> sA(new A);
sA->a = 4; // compile-error
return sA;
}
int main(int argc, char** argv) {
f1();
f2();
return 0;
}

Related

Is this indirect const access an UB?

When I was checking some code today, I noticed an old method for implementing std::enable_shared_from_this by keeping a std::weak_ptr to self in the constructor. Somthing like this:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
// use m_weak.lock() to access the object
//...
private:
X() {}
std::weak_ptr<X> m_weak;
};
But then something came to me regarding constness of this object. Check the following code:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void indirectUpdate() const {
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
private:
X() {}
std::weak_ptr<X> m_weak;
int val = 0;
};
int main() {
auto x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
In this code, indirectUpdate() is a const method and it should not update our object, but in fact it does. Because std::weak_ptr.lock() returns a non-const shared_ptr<> even though the method is const. So you will be able to update your object indirectly in a const method. This will not happen in case of std::enable_shared_from_this because shared_from_this returns a shared pointer to const ref of object in const method. I wonder if this code is UB or not. I feel it should be, but I'm not sure. Any idea?
Update:
Sorry, it seems that my question was not relayed correctly. I meant even if we have a const pointer, we lose that constness via this method. following code shows that:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void show() const { std::cout << "const \n";}
void show() { std::cout << "non-const\n";}
void indirectUpdate() const {
show();
m_weak.lock()->show();
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
int val = 0;
private:
X() {}
std::weak_ptr<X> m_weak;
};
int main() {
// Here we have a const pointer
std::shared_ptr<const X> x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
and output will be following:
0
const
non-const
1
which shows losing constness.
The object that is modified is not const. There is no undefined behavior.
Add a method like this:
#include <memory>
#include <iostream>
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void show() const { std::cout << "const \n";}
void show() { std::cout << "non-const\n";}
void indirectUpdate() const {
m_weak.lock()->show();
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
private:
X() {}
std::weak_ptr<X> m_weak;
int val = 0;
};
int main() {
auto x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
To get this output:
0
non-const
1
Modifying an object via a const mehtod is ok, as long as the method only modifies an object that is actually not const.
It is similar to using a const & to a non-const object. You may cast away constness and modify it as long as the object is really not const:
#include <iostream>
int main() {
int x = 0;
const int& ref = x;
const_cast<int&>(ref) = 42;
std::cout << x;
}
I also see no danger of misusing the pattern in your code, because once the object is const you won't be able to assign to its val member and all is fine with constcorrectness.
In your Update you have a const pointer in main but the object is still not const. Consider this simpler example:
#include <iostream>
struct foo {
static foo* create(){
auto x = new foo();
x->self = x;
return x;
}
void bar() const {
this->self->non_const();
}
void non_const() {
std::cout << "Hello World\n";
}
foo* self;
};
int main() {
const foo* f = foo::create();
f->bar();
delete f;
}
Its not quite the same as yours, but it has similar effect of calling a non-const method on a seemingly const object. Though its all fine.
The only foo object is that created in foo::create, it is not constant. In main we have a const foo* to that object. main can only call the const member bar. Inside bar the this pointer is a const foo*, but self does not point to a const foo. self itself is `const, but not the object it points to.

Multiple operator[] overloads

Take a look at this simple array class
class Array {
const unsigned int _size;
int _array[100];
public:
Array() : _size(100) {
for(unsigned int i = 0; i < _size; i++)
_array[i] = 0;
}
int& operator[](unsigned int index) {
cout << "normal operator[].\n";
return _array[index];
}
const int& operator[](unsigned int index) const {
cout << "const operator[].\n";
return _array[index];
}
};
int main()
{
Array a;
a[3] = 1;
cout << a[3] << "\n";
system("pause");
return 0;
}
The "normal operator[]" line is executed twice, though I would expect the second call (cout << a[3] << "\n";) to be using the const version of the overloaded operator, because it doesn't change the array itself.
Why is that? Is there a way to force the const version to be called as I wish?
When you have an overloaded const version of a method, the const version will be called when the object is const. For example:
#include <iostream>
using namespace std;
class MyClass
{
public:
void foo()
{
cout << "foo()" << endl;
}
void foo() const
{
cout << "foo() const" << endl;
}
};
int main()
{
MyClass a;
const MyClass b;
a.foo();
b.foo();
return 0;
}
will call the normal foo() for the object a, and the const version for the object b.
In your case, you just have to avoid trying to assign to the const version. For example:
Array a;
const Array b;
a[3] = 1;
// b[3] = 1; // error
cout << a[3] << "\n";
cout << b[3] << "\n";
works fine. But if you try to make the assignment to b, you get a compile error.
std::ostream &operator<<(int x) doesn't take its parameter as const (because const isn't useful when passing by value), so the non-const operator[] can be called.
So, when will const operator[] be called?
It is true that a const vector variable declaration is almost always useless aside from some edge cases. The primary reason const operator[] is important, and the most often you will see it used, is calling it on a reference parameter.
int readStuff(const std::vector<int> &dontMutateMe) {
return dontMutateMe[42]; // const
}
Constant reference parameters are valuable, and this code wouldn't work without const operator[].

Lifetime of const references bound to destroyed stack variable

I'm wondering if it's by chance a pointer to const reference bound to a destroyed stack variable can be working.
I read const reference lifetime is extended on rvalues, so this is "normal" const reference works but at the end of the ctor of Storage ref should be destroyed, isn't it ?
Does const reference lifetime is also extended because I retrieved it's address in a pointer or is this pure luck ?
Live example
#include <iostream>
class Storage
{
public:
Storage(const int& ref)
{
p = &ref;
}
const int* Get() const
{
return p;
}
private:
const int* p;
};
int main()
{
Storage* s = nullptr;
{
int someValue = 42;
std::cout << &someValue << std::endl;
s = new Storage(someValue);
}
const int* p = s->Get();
std::cout << p << std::endl;
std::cout << *p << std::endl;
}
It's also working with a struct Live example
#include <iostream>
struct Dummy
{
int value;
};
class Storage
{
public:
Storage(const Dummy& ref)
{
p = &ref; // Get address of const reference
}
const Dummy* Get() const
{
return p;
}
private:
const Dummy* p;
};
int main()
{
Storage* s = nullptr;
{
Dummy dummy;
dummy.value = 42;
std::cout << &dummy << std::endl;
s = new Storage(dummy);
}
const Dummy* p = s->Get();
std::cout << p << std::endl;
std::cout << p->value << std::endl;
}
Your s variable indeed has a dangling pointer as someValue has fallen out of scope. Your code therefore exhibits undefined behavior.
Your comment about "const reference lifetime is extended on rvalues" is true in some circumstances, but someValue is an lvalue.
The compiler probably assigns the stack space for all the local variables at the start, so someValue is still in the same place in memory even after it goes out of scope. Of course a different compiler might do something different, and it could get overwritten by a subsequent local variable.
For your second example if you wrote a ~Dummy(){ value=0; }, then it wouldn't work, proving that the lifetime of the dummy object hasn't been extended.

Pointer to int. C++

I need to pass to function pointer to int.
Now if I want to pass 5 I'm doing it like this:
int * i = NULL;
int b = 5;
i = &b;
Is there any better way to write it shorter?
I want to pass bytes that are in i int to this function:
void Write2Asm(void* pxAddress, BYTE * MyBytes, int size)
You can just pass &b to the function; no need for an intermediate pointer variable.
Why to create a pointer variable?. Why can't you do it like this?.
int b = 5;
func(&b)
void f(int *i)
{
//...
}
int b = 5;
f(&b);
is enough!
There are a few old C APIs that always take arguments by pointer, even if they're effectively read-only booleans etc.. I'm not recommending it - more for interest's sake - but if you want to go the whole hog you could do something hackish like:
#include <iostream>
struct X
{
X(int n) : n_(n) { std::cout << "X()\n"; }
~X() { std::cout << "~X()\n"; }
operator int&() { return n_; }
operator const int() const { return n_; }
int* operator&() { return &n_; }
const int* operator&() const { return &n_; }
int n_;
};
// for a function that modifies arguments like this you'd typically
// want to use the modified values afterwards, so wouldn't use
// temporaries in the caller, but just to prove this more difficult
// case is also possible and safe...
void f(int* p1, int* p2)
{
std::cout << "> f(&" << *p1 << ", &" << *p2 << ")\n";
*p1 += *p2;
*p2 += *p1;
std::cout << "< f() &" << *p1 << ", &" << *p2 << "\n";
}
int main()
{
// usage...
f(&X(5), &X(7));
std::cout << "post\n";
}
Crucially, the temporaries are valid until after the function call f(...) exits.

Member pointer to array element

It's possible to define a pointer to a member and using this later on:
struct foo
{
int a;
int b[2];
};
int main()
{
foo bar;
int foo::* aptr=&foo::a;
bar.a=1;
std::cout << bar.*aptr << std::endl;
}
Now I need to have a pointer to a specific element of an array, so normally I'd write
int foo::* bptr=&(foo::b[0]);
However, the compiler just complains about an "invalid use of non-static data member 'foo::b'"
Is it possible to do this at all (or at least without unions)?
Edit: I need a pointer to a specific element of an array, so int foo::* ptr points to the second element of the array (foo::b[1]).
Yet another edit: I need to access the element in the array by bar.*ptr=2, as the pointer gets used somewhere else, so it can't be called with bar.*ptr[1]=2 or *ptr=2.
However, the compiler just complains about an "invalid use of non-static data member 'foo::b'"
This is because foo::a and foo::b have different types. More specifically, foo::b is an array of size 2 of ints. Your pointer declaration has to be compatible i.e:
int (foo::*aptr)[2]=&foo::b;
Is it possible to do this at all (or at least without unions)?
Yes, see below:
struct foo
{
int a;
int b[2];
};
int main()
{
foo bar;
int (foo::*aptr)[2]=&foo::b;
/* this is a plain int pointer */
int *bptr=&((bar.*aptr)[1]);
bar.a=1;
bar.b[0] = 2;
bar.b[1] = 11;
std::cout << (bar.*aptr)[1] << std::endl;
std::cout << *bptr << std::endl;
}
Updated post with OP's requirements.
The problem is that, accessing an item in an array is another level of indirection from accessing a plain int. If that array was a pointer instead you wouldn't expect to be able to access the int through a member pointer.
struct foo
{
int a;
int *b;
};
int main()
{
foo bar;
int foo::* aptr=&(*foo::b); // You can't do this either!
bar.a=1;
std::cout << bar.*aptr << std::endl;
}
What you can do is define member functions that return the int you want:
struct foo
{
int a;
int *b;
int c[2];
int &GetA() { return a; } // changed to return references so you can modify the values
int &Getb() { return *b; }
template <int index>
int &GetC() { return c[index]; }
};
typedef long &(Test::*IntAccessor)();
void SetValue(foo &f, IntAccessor ptr, int newValue)
{
cout << "Value before: " << f.*ptr();
f.*ptr() = newValue;
cout << "Value after: " << f.*ptr();
}
int main()
{
IntAccessor aptr=&foo::GetA;
IntAccessor bptr=&foo::GetB;
IntAccessor cptr=&foo::GetC<1>;
int local;
foo bar;
bar.a=1;
bar.b = &local;
bar.c[1] = 2;
SetValue(bar, aptr, 2);
SetValue(bar, bptr, 3);
SetValue(bar, cptr, 4);
SetValue(bar, &foo::GetC<0>, 5);
}
Then you at least have a consistent interface to allow you to change different values for foo.
2020 update, with actual solution:
The Standard does currently not specify any way to actually work with the member pointers in a way that would allow arithmetics or anything to get the pointer to the "inner" array element
OTOH, the standard library now has all the necessities to patch the appropriate member pointer class yourself, even with the array element access.
First, the member pointers are usually implemented as "just offsets", although quite scary. Let's see an example (on g++9, arch amd64):
struct S { int a; float b[10]; };
float(S::*mptr)[10] = &S::b;
*reinterpret_cast<uintptr_t *>(&mptr) //this is 4
int S::*iptr = &S::a;
*reinterpret_cast<uintptr_t *>(&iptr) //this is 0
iptr = nullptr;
*reinterpret_cast<uintptr_t *>(&iptr) //this seems to be 18446744073709551615 on my box
Instead you can make a bit of a wrapper (it's quite long but I didn't want to remove the convenience operators):
#include <type_traits>
template<class M, typename T>
class member_ptr
{
size_t off_;
public:
member_ptr() : off_(0) {}
member_ptr(size_t offset) : off_(offset) {}
/* member access */
friend const T& operator->*(const M* a, const member_ptr<M, T>& p)
{ return (*a)->*p; }
friend T& operator->*(M* a, const member_ptr<M, T>& p)
{ return (*a)->*p; }
/* operator.* cannot be overloaded, so just take the arrow again */
friend const T& operator->*(const M& a, const member_ptr<M, T>& p)
{ return *reinterpret_cast<const T*>(reinterpret_cast<const char*>(&a) + p.off_); }
friend T& operator->*(M& a, const member_ptr<M, T>& p)
{ return *reinterpret_cast<T*>(reinterpret_cast<char*>(&a) + p.off_); }
/* convert array access to array element access */
member_ptr<M, typename std::remove_extent<T>::type> operator*() const
{ return member_ptr<M, typename std::remove_extent<T>::type>(off_); }
/* the same with offset right away */
member_ptr<M, typename std::remove_extent<T>::type> operator[](size_t offset) const
{ return member_ptr<M, typename std::remove_extent<T>::type>(off_)+offset; }
/* some operators */
member_ptr& operator++()
{ off_ += sizeof(T); return *this; };
member_ptr& operator--()
{ off_ -= sizeof(T); return *this; };
member_ptr operator++(int)
{ member_ptr copy; off_ += sizeof(T); return copy; };
member_ptr operator--(int)
{ member_ptr copy; off_ -= sizeof(T); return copy; };
member_ptr& operator+=(size_t offset)
{ off_ += offset * sizeof(T); return *this; }
member_ptr& operator-=(size_t offset)
{ off_ -= offset * sizeof(T); return *this; }
member_ptr operator+(size_t offset) const
{ auto copy = *this; copy += offset; return copy; }
member_ptr operator-(size_t offset) const
{ auto copy = *this; copy -= offset; return copy; }
size_t offset() const { return off_; }
};
template<class M, typename T>
member_ptr<M, T> make_member_ptr(T M::*a)
{ return member_ptr<M, T>(reinterpret_cast<uintptr_t>(&(((M*)nullptr)->*a)));}
Now we can make the pointer to the array element directly:
auto mp = make_member_ptr(&S::b)[2];
S s;
s->*mp = 123.4;
// s.b[2] is now expectably 123.4
Finally, if you really, really like materialized references, you may get a bit haskell-lensish and make them compose:
// in class member_ptr, note transitivity of types M -> T -> TT:
template<class TT>
member_ptr<M,TT> operator+(const member_ptr<T,TT>&t)
{ return member_ptr<M,TT>(off_ + t.offset()); }
// test:
struct A { int a; };
struct B { A arr[10]; };
B x;
auto p = make_member_ptr(&B::arr)[5] + make_member_ptr(&A::a)
x->*p = 432.1;
// x.arr[5].a is now expectably 432.1
typedef int (foo::*b_member_ptr)[2];
b_member_ptr c= &foo::b;
all works.
small trick for member and function pointers usage.
try to write
char c = &foo::b; // or any other function or member pointer
and in compiller error you will see expected type, for your case int (foo::*)[2].
EDIT
I'm not sure that what you want is legal without this pointer. For add 1 offset to your pointer you should get pointer on array from your pointer on member array. But you can dereference member pointer without this.
You can't do that out of the language itself. But you can with boost. Bind a functor to some element of that array and assign it to a boost::function:
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
struct test {
int array[3];
};
int main() {
namespace lmb = boost::lambda;
// create functor that returns test::array[1]
boost::function<int&(test&)> f;
f = lmb::bind(&test::array, lmb::_1)[1];
test t = {{ 11, 22, 33 }};
std::cout << f(t) << std::endl; // 22
f(t) = 44;
std::cout << t.array[1] << std::endl; // 44
}
I'm not sure if this will work for you or not, but I wanted to do a similar thing and got around it by approaching the problem from another direction. In my class I had several objects that I wanted to be accessible via a named identifier or iterated over in a loop. Instead of creating member pointers to the objects somewhere in the array, I simply declared all of the objects individually and created a static array of member pointers to the objects.
Like so:
struct obj
{
int somestuff;
double someotherstuff;
};
class foo
{
public:
obj apples;
obj bananas;
obj oranges;
static obj foo::* fruit[3];
void bar();
};
obj foo::* foo::fruit[3] = { &foo::apples, &foo::bananas, &foo::oranges };
void foo::bar()
{
apples.somestuff = 0;
(this->*(fruit[0])).somestuff = 5;
if( apples.somestuff != 5 )
{
// fail!
}
else
{
// success!
}
}
int main()
{
foo blee;
blee.bar();
return 0;
}
It seems to work for me. I hope that helps.