Search code examples
c++c++11shared-ptrpointer-to-member

Pointer to member variable of shared_ptr


What is a safe way to accessing member variables through a shared object in C++?

In the code below, I make a shared variable and then a pointer to a member variable of it. However, the use_count remains unchanged and when I reset the shared variable the original variable is reset but not the pointer to member.

In other words, I could introduce some bugs by using b. The object it is pointing to shouldn't exist anymore.

#include <iostream>
#include <memory>

using namespace std;

struct A
{
    int y;
    A(int x)
    {
        y = x;
    }
};

int main()
{
    auto a = make_shared<A>(1);
    cout << "a count: " << a.use_count() << endl; //prints a count: 1
    auto b = a->y;
    cout << "a count: " << a.use_count() << endl; //still prints a count: 1

    a.reset();

    cout << "a value: " << a << endl; //prints a value: 0
    cout << "b value: " << b << endl; //prints b value: 1

    return 0;
}

Solution

  • What is a safe way to accessing member variables through a shared object in C++?

    You are already doing it. The code you showed is safe.

    In the code below, I make a shared variable and then a pointer to a member variable of it.

    No, you don't. A::y is an int. In the auto b = a->y; statement, auto deduces to int, not to int& or int*. So, you are creating a new int whose value is a copy of y. There is no pointer to y.

    If you wanted something like that, you would have needed to use one of these instead:

    auto &b = a->y;
    ... 
    cout << "b value: " << b << endl;
    

    auto *b = &(a->y); // or just: auto b = ...
    ... 
    cout << "b value: " << *b << endl;
    

    However, the use_count remains unchanged

    Correct, because you are not assigning a to another instance of shared_ptr<A>. That is what use_count represents - the number of shared_ptr objects that are sharing the same object in memory.

    when I reset the shared variable the original variable is reset but not the pointer to member.

    Of course, because b is independent of a and is not a pointer to anything related to a.

    In other words, I could introduce some bugs by using b.

    No, because b is not linked to a, so resetting a has no effect on b.

    Now, if you did manage to accomplish what you are asking for (making b be a pointer to y), it is your responsibility to make sure the A object that y was accessed from remains valid in memory until you are done using b, otherwise dereferencing b will be undefined behavior. The STL won't save you from doing something stupid behind its back, like accessing an A object's member via a raw pointer after the object has been destroyed.