mercredi 12 août 2020

Initialize field with raw pointer to object after base class constructed with moved unique_ptr to same object

I have an object Foo owned by Owner and no one else. I create an object of class Derived that inherits Owner, passing it a unique_ptr to a newly created Foo. Derived has a member of class User that also needs to use Foo, but doesn't own it, so it gets only a raw pointer to it.

#include <memory>
#include <iostream>
using namespace std;

struct Foo {
  void talk() { cout << "foo" << endl; }
};

struct User {
  Foo *foo;
  User(Foo *_foo): foo(_foo) {};
  void use() { foo->talk(); } //potential disaster if foo's memory has changed
};

struct Owner {
  unique_ptr<Foo> foo;
  Owner(unique_ptr<Foo> _foo): foo(move(_foo)) {};
};

struct Derived : public Owner {
  User user;
  Derived(unique_ptr<Foo> _foo)
  : Owner {move(_foo)},
    user{_foo.get()}  //potential disaster: _foo has already been move()'d, can't get()!
  {};
  void use() { user.use(); };
};

int main() {
  Derived d(make_unique<Foo>());
  //do other stuff
  d.use();  //potential disaster
}

The problem is that in the initialization list of Derived, I need to move() the Foo to pass it to Owner's constructor (which takes a unique_ptr<Foo>, because it is the owner), and also pass a raw pointer to the Foo to User. But by the time the User gets initialized, the unique_ptr<Foo> has already been moved and foo.get() may point to an invalid location!

What's a good way to make sure User gets a valid (non-owning) pointer to Foo and Owner still gets its unique_ptr<Foo>?

Aucun commentaire:

Enregistrer un commentaire