基本上我有这个设置:
class B { /* ... */};
class C1 : public B { /* ... */};
class C2 : public B { /* ... */};
class X
{
std::vector<shared_ptr<B>> m_vec;
void addToVector(B* b);
}
addToVector
无法知道有多少班级来自B而且不应该关心。它会像这样调用:
someFunction() {
C1 tmp;
/* do something with tmp */
m_myX.addToVector(&tmp);
}
所以在someFunction
结束时,tmp超出范围并将被删除。 addToVector
必须将一个shared_ptr推送到向量中的tmp副本,但它怎么能这样做呢?
void X::addToVector(B* b)
{
int i = sizeof(b); // allways sizeof(B) :(
shared_ptr<B> np(b);
m_vec.push_back(np); // garbage collected after calling fn returns :(
}
它应该做的是:
我该怎么做?
答案 0 :(得分:4)
您正在堆栈上创建一个对象,然后将其地址提供给shared_ptr
,它将尝试delete
堆栈中的对象,这是未定义的行为。
解决方案是停止这样做:
void someFunction() {
C1* c = new C1;
/* do something with *c */
m_myX.addToVector(c);
}
现在堆上有一个对象,可以由shared_ptr
拥有。没有必要复制它。
只有当B
具有虚拟析构函数时,这才能正常工作,但可以通过首先创建shared_ptr来避免(并且可以使代码更安全,更清晰):
void someFunction() {
auto c = std::make_shared<C1>();
/* do something with *c */
m_myX.addToVector(c);
}
void X::addToVector(std::shared_ptr<B> b)
{
m_vec.push_back(np);
}
现在堆对象在创建后由shared_ptr
管理,然后安全地存储在向量中。
答案 1 :(得分:2)
你的'someFunction'看起来很奇怪......(为什么不首先将tmp
创建为shared_ptr
?)
要使它工作,你必须创建'虚拟构造函数' - 在B中添加虚拟方法B* deepCopy() const
,并在所有子类中实现它,它的主体应该基于模式:{ return new DerivedType(*this); }
如果您想要干净 - 请deepCopy
返回shared_ptr
并使用make_shared
。