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();
As this link points out, it is safe and not UB to delete this
in a method, even if it is a bit confusing.
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.