1
votes

I'm just starting out with C++ and trying to get my head around smart pointers. Obviously, the following code will crash (I suppose it's because the assignment created a copy of the shared_ptr?). Is there a way to keep foo.Other updated by calling some kind of set method on ptrs[3]?

class Foo
{
public:
    int X;
    std::shared_ptr<Foo> Other;

    Foo() : X(10) { }
};

int main()
{
    Foo foo;

    std::vector<std::shared_ptr<Foo>> ptrs(10);

    foo.Other = ptrs[3];

    std::shared_ptr<Foo> other = std::shared_ptr<Foo>(new Foo());
    ptrs[3] = other;

    std::cout << foo.Other->X << std::endl; // throws Access violation exception

    return 0;
}

Edit: This is the exception I'm getting since it's pointing to null:

First-chance exception at 0x01219AEF in Test.exe: 0xC0000005: Access violation reading location 0x00000000. Unhandled exception at 0x01219AEF in Test.exe: 0xC0000005: Access violation reading location 0x00000000.

2
One thing you should definitely be doing is using std::make_shared instead of std::shared_ptr<Foo>(new Foo()) - chris

2 Answers

5
votes

You seem to be under the impression that doing this:

foo.Other = ptrs[3];

creates some sort of relationship between the two objects so that if you change one of them then the other also changes.

That's not how shared_ptr works. The thing it points to is shared, and changing that thing means all the pointers to it see the changed value (because there's only one value, which is owned by multiple objects) so this works:

std::shared_ptr<int> p = std::make_shared<int>(1);
assert( *p == 1 );
std::shared_ptr<int> q = p;
*q = 2;
assert( *p == 1 );

But the shared_ptr objects themselves don't all start being identical copies of each other.

They point to the same thing, that doesn't mean they are the same thing.

If you change ptrs[3] to point to something different that doesn't also make foo.Other point to something different. If it did that would make shared_ptr almost useless, you couldn't usefully have multiple owners of an object, because as soon as one of them stopped owning the object all the others would stop owning it too and it would be destroyed.

Instead only the shared_ptr you update gets a new value, other shared_ptrs keep their old value.

std::shared_ptr<int> p = std::make_shared<int>(1);
assert( *p == 1 );
std::shared_ptr<int> q = p;
assert( *q == 1 );
assert( p == q );
assert( p.get() == q.get() );
assert( *p == *q );
p = std::make_shared<int>(2);
assert( *p == 2 );
assert( *q == 1 );
assert( p != q );
assert( p.get() != q.get() );
assert( *p != *q );
4
votes

Irrelevant of shared_ptr and other stuff, all your code boils down to:

int a = 0;
int b = a;
a = 42;
// why b isn't == to 42?

Think about it for a second... I'm afraid that's as much an answer as I can provide.

Don't hesitate to ask for clarification, I'll gladly answer, but before you do please think about it again.