What happens to the reference of an object managed by a unique pointer that has been moved?

Viewed 62

If I crate an object that is managed by a unique pointer such as:

auto pObjectA = std::make_unique<A>();

But I need this object as a parameter of another object:

auto pObjectB = std::make_unique<B>(*objectA);

If objectA is later moved with std::move, will the reference passed to objectB still be valid?

Edit:

class A
{
 //(...)
}

class B 
{
  public:
    B(A& objA): m_rObjectA(objA){}
    ~B();
    void DoSomehting() { /*something that calls a method in A*/ }

  private:
    A& m_rObjectA;
}    

int main()
{
  auto pObjectA = std::make_unique<A>();
  auto pObjectB = std::make_unique<B>(*pObjectA);

  std::unique_ptr<A> pA = std::move(pObjectA);

  pObjectB.DoSomething();
}
1 Answers

Yes, the reference passed to objectB will still be valid since std::make_unique<B>(*objectA) will copy the object referenced by unique pointer objectA and use the copy object as its property instead of storing the original object. Therefore, if objectA is moved using the function std::move, objectB's A object won't be affected. Here's the demo code for the affect of std::move on objectA and objectB

#include <iostream>
using namespace std;

class A {
  public:
    string value;
    A() {
      value = "ABC";
    }
    void print_values() {
      std::cout << "value: " << value << std::endl;    
    }
};

class B {
    A a_prop;
  public:
    B(A a) {
      a_prop = a;
    }
    void print_values() {
      a_prop.print_values();
    }
};

int main() {
  auto objectA = std::make_unique<A>();
  // objectB->a_prop will have a different A object from the one referenced by objectA
  auto objectB = std::make_unique<B>(*objectA);
  objectA->value.replace(objectA->value.begin(), objectA->value.end() - 1, "ED");
  objectA->print_values(); // Will display "EDC"
  objectB->print_values(); // Will display "ABC"

  // Object A that is referenced by objectA will now be referenced by objectAMoved
  // objectA will be nullptr
  auto objectAMoved = std::move(objectA);
  objectAMoved->print_values(); // Will display "EDC"
  
  objectAMoved->value.replace(objectAMoved->value.begin(), objectAMoved->value.end() - 1, "FG");

  objectB->print_values(); // Will display "ABC"
  objectAMoved->print_values(); // Will display "FGC"

  if (objectA == nullptr) {
    cout << "A is nullptr" << endl; // This will be printed out
  } else {
    objectA->print_values(); // This will cause segmentation fault
  }
}

Update: If you set A& a_prop and B(A& a) : a_prop(a), it will still be valid but you will instead store the original object referenced by objectA in a_prop instead of a copy. After the object referenced by objectA is moved to objectAMoved, a_prop is still valid as it store the reference to original object A instead of a unique_ptr<A> like objectA.

#include <iostream>
using namespace std;

class A {
  public:
    string value;
    A() {
      value = "ABC";
    }
    void print_values() {
      std::cout << "value: " << value << std::endl;    
    }
};

class B {
    A& a_prop;
  public:
    B(A& a) : a_prop(a) {
    }
    void print_values() {
      a_prop.print_values();
    }
};

int main() {
  auto objectA = std::make_unique<A>();
  auto objectB = std::make_unique<B>(*objectA);

  objectA->value.replace(objectA->value.begin(), objectA->value.end() - 1, "ED");
  objectA->print_values(); // Will display "EDC"
  objectB->print_values(); // Will display "EDC"

  auto objectAMoved = std::move(objectA);
  objectAMoved->print_values(); // Will display "EDC"
  
  objectAMoved->value.replace(objectAMoved->value.begin(), objectAMoved->value.end() - 1, "FG");

  objectB->print_values(); // Will display "FGC"
  objectAMoved->print_values(); // Will display "FGC"

  if (objectA == nullptr) {
    cout << "A is nullptr" << endl;
  } else {
    objectA->print_values(); // This will cause segmentation fault segmentation fault 
  }
}
Related