我有一个班级,它拥有它的孩子:
class Child
{
public:
Child() {}
~Child() {}
};
class Parent : public QObject
{
Q_OBJECT
public:
explicit Parent(QObject *parent = 0): QObject(parent) {}
~Parent()
{
qDeleteAll(m_children);
}
void addChild(Child *ch)
{
m_children.append(ch);
}
private:
QList<Child *> m_children;
};
使用 Child
方法添加到
Parent
类的
addChild
实例将在 Parent
被删除时被删除。
以下使用方式会导致双子破坏:
int main()
{
{
Parent father;
Child child;
father.addChild( &child );
}
//child is out of scope now and gets destroyed
//father gets destroyed too
//father's destructor deletes child AGAIN!
//crash!
return 0;
}
如何使用智能指针来防止这种情况?
QPointer
可用于 QObject
继承类,这使得它对于这种情况毫无用处。我还能怎样防止这种情况发生?
这与双重销毁无关。您无法删除堆栈对象。 相反,你应该在堆中分配它:
Parent father;
Child* child = new Child();
father.addChild( child );
我猜你的第一个问题是关于子元素的所有权。 如果你想让Parent类处理Child的生命周期,可以使用智能指针来解决。
class Parent : public QObject
{
using ptr = std::shared_ptr<Child>;
Q_OBJECT
public:
explicit Parent(QObject *parent = 0): QObject(parent) {}
void addChild(const ptr& ch)
{
m_children.append(ch);
}
private:
QList<ptr> m_children;
};
然后:
{
Parent father;
auto child = std::make_shared<Child>();
father.addChild( child );
}
如果您想保留实际使用情况,那么您必须制作副本并存储这些副本。
Parent
取得了 Child
的所有权,而它不应该出现在您的样本中。
可能的解决方案包括:
Child
应该在其析构函数中将其自身从其父级中删除,以防止错误删除。Parent
接口以明确强制所有权转让:void addChild(std::share_ptr<Child> ch)
或void addChild(std::unique_ptr<Child> ch)
。Parent
中维护2个容器,一个有所有权,一个没有所有权。这是使用 std::shared_ptr: 的可能解决方案:
#include <iostream>
#include <memory>
#include <vector>
class Child
{
public:
Child(std::string name)
{
name_ = name;
}
~Child()
{
std::cout << "~Child: " << name_ << std::endl;
}
private:
std::string name_;
};
class Parent
{
public:
~Parent()
{
std::cout << "~Parent" << std::endl;
}
void addChild(std::shared_ptr<Child> ch)
{
m_children.push_back(ch);
}
private:
std::vector <std::shared_ptr<Child> > m_children;
};
int main()
{
std::shared_ptr<Child> john (new Child("John"));
std::cout << "John created" << std::endl;
{
Parent father;
{
std::shared_ptr<Child> jack ( new Child("Jack"));
std::cout << "Jack created" << std::endl;
father.addChild( john );
father.addChild( jack );
std::cout << "added John and Jack to father" << std::endl;
}
std::cout << "jack left scope" << std::endl;
// jack is out of scope now but since it's a smart pointer
// and father still holds a reference to the memory it
// referred to that memory is still allocated.
}
std::cout << "father left scope" << std::endl;
// father gets destroyed here and with it its m_children.
// As the list goes so does the last reference to the memory
// allocated for child and the child gets destroyed.
// Note that jack doesn't get destroyed here. Even though it was
// one of the children. The reason is that the orphan smart
// pointer is still in scope.
return 0;
}
注意:这并不能让父级控制其子级的生命周期。 父对象可以与子对象关联,但子对象现在仅在对其的最后一个引用被销毁时才会被销毁。如果有其他东西持有指向它的智能指针(如上面所示的 john 的情况),则孩子有可能“幸存”其所有父母。如果您的目的是让子对象仅属于一个父对象并与其父对象一起销毁,则应将子对象创建逻辑封装在父对象中,以便子对象只能由父对象创建。