Search code examples
c++shared-ptrself-reference

re-assigning shared_ptr from within object pointed to


consider the following code

struct base {
  virtual void bar(std::shared_ptr<base>&) = 0;
};

struct foo1 : base { /* ... */ };

struct foo2 : base {
  void bar(std::shared_ptr<base>&obj)
  {
    // ...
    if(some_condition)
      obj = std::make_shared<foo1>();  // re-assign obj
    // ...
  }
};

std::shared_ptr<base> x = std::make_shared<foo2>();
x->bar(x);                             // last line

Does this code envoke UB? (note: the re-assigning of obj will destroy the this object of call foo2::bar when called from the last line). If no data of bar are accessed thereafter, is the code still okay?

An alternative way of coding this would be

struct base {
  virtual std::shared_ptr<base> bar(std::shared_ptr<base>) = 0;
};
struct foo1 : base { /* ... */ };

struct foo2 : base {
  std::shared_ptr<base> bar(std::shared_ptr<base> obj)
  {
    // ...
    if(some_condition)
      obj = std::make_shared<foo1>();
    // ...
    return obj;
  }
};

std::shared_ptr<base> x = std::make_shared<foo2>();
x=x->bar(x);

which should be safe in any case, shouldn't it? Is the extra copying in this code a performance issue?


edit. After Chris answer, I had a look at shared_from_this, which allows the following alternative implementation

struct base : std::enable_shared_from_this<base> {
  virtual std::shared_ptr<base> bar() = 0;
};
struct foo1 : base { /* ... */ };

struct foo2 : base {
  std::shared_ptr<base> bar()
  {
    auto obj = shared_from_this();
    if(some_condition)
      obj = std::make_shared<foo1>();
    // ...
    return obj;
  }
};

std::shared_ptr<base> x = std::make_shared<foo2>();
x=x->bar();

Solution

  • As this link points out, it is safe and not UB to delete this in a method, even if it is a bit confusing.

    Is it safe to `delete this`?

    I don't think the extra copying is an issue. To be sure you would have to profile. Absent profiling info, if it were me I would prefer second approach to first b/c it's simpler for the programmer to understand, but it's largely opinion.

    You might also want to look into the shared_from_this template in C++11, if you want to make it simpler for objects to manipulate shared pointers to themselves and such.