Reputation: 10539
Consider following code:
#include <stdio.h>
#include <memory>
class Sub{};
class SubImpl : public Sub {};
class A{
public:
A(Sub & sub) : sub(sub){}
void doSomething(){
// ...
};
private:
Sub & sub;
};
std::unique_ptr<A> factory(){
SubImpl sub;
return std::unique_ptr<A>(new A(sub));
}
int main(){
auto a = factory();
a->doSomething();
}
This code have problem - Sub object lifetime is not same as A object, and A::sub
reference is dangled.
In order to fix this, I can do:
unique_ptr
/ shared_ptr
or to use raw pointerIs there any other way I can fix this?
Upvotes: 2
Views: 1293
Reputation: 15334
It seems you have two choices, either the lifetime of SubImpl
is controlled by A
in which case I see no alternative to using a pointer, preferably a unique_ptr
, like bolov has shown. And I don't think there is anything particularly wrong with that.
Or the lifetime of SubImpl
is controlled by something outside of A
in which case you can use references.
For example, you could change the factory so that it is an object that owns the SubImpl
. Here is a simplistic example:
// definitions of Sub, SubImpl and A as before...
class SubOwner {
SubImpl sub;
public:
A createA() const {
return A(sub);
}
};
int main(){
SubOwner so;
auto a = so.createA();
a.doSomething();
}
That's fine if you only want one SubImpl
but it is possible that you want to use your factory to create many A
s and each A
should have a reference to a different SubImpl
. In which case you could have an object that owns a collection of SubImpl
:
class SubOwner {
// Using deque instead of vector to avoid reference invalidation.
// Could use vector if you knew how many SubImpl you need up front.
std::deque<SubImpl> subs;
public:
A createA() const {
subs.emplace_back();
return A(subs.back());
}
};
int main(){
SubOwner so;
auto a1 = so.createA();
auto a2 = so.createA();
a1.doSomething();
a2.doSomething();
}
Providing SubOwner
and A
are themselves owned by the same object or local to the same scope then you can guarantee that the lifetime of SubImpl
will be the same as A
.
Upvotes: 1
Reputation: 75815
Use unique_ptr
if the object sub
is used solely to create only one A
object. Use shared_ptr
otherwise.
class Sub{};
class SubImpl : public Sub {};
class A{
public:
A(std::unique_ptr &&sub) : sub(std::move(sub)){}
void doSomething(){
// ...
};
private:
std::unique_ptr sub;
};
std::unique_ptr<A> factory(){
auto sub = std::make_unique<SubImpl>();;
return std::make_unique<A>(std::move(sub));
}
int main(){
auto a = factory();
a->doSomething();
}
Upvotes: 2