我有一个课程,它拥有它的孩子的所有权:
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
个继承的类,这使得它对这种情况毫无用处。我怎么能阻止这个?
答案 0 :(得分:5)
这不是关于双重破坏。你不能删除堆栈对象。 相反,您应该在堆中分配它:
Parent father;
Child* child = new Child();
father.addChild( child );
答案 1 :(得分:1)
如果你看一下constructor of QObject,你会发现它需要一个QObject作为父母,所以不要重新发明轮子,除非你已经在使用它(看起来你不是),您可以使用Qt的父子层次结构: -
Parent* parent = new Parent;
Child* Child1 = new Child(parent);
然后,您可以根据需要检索父级children的列表,而不必担心管理子级,因为它们在删除父级时会被删除。
如果要在创建子项目后设置子项,请调用子项的setParent函数。
答案 2 :(得分:0)
您可以使用std::tr1::shared_pointer
here作为教程。如果你的编译器中没有这个,你可以使用boost::shared_pointer
,描述here你也可以implement自己的智能指针。
答案 3 :(得分:0)
我猜你的第一个问题是关于子元素的所有权。 如果您希望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 );
}
如果您想保留实际使用情况,则必须制作副本并存储这些副本。
答案 4 :(得分:0)
Parent
取得Child
的所有权,而不应放在样本中。
可能的解决方案包括:
Child
应该在其析构函数中将其自身从父目录中移除,以防止错误删除。Parent
界面以明确强制所有权转让:void addChild(std::share_ptr<Child> ch)
或void addChild(std::unique_ptr<Child> ch)
。Parent
中维护2个容器,一个拥有所有权,另一个拥有所有权。答案 5 :(得分:0)
这是使用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;
}
注意:这不会让父母控制孩子的生命周期。 Parent对象可以与Child对象关联,但是现在只有在对对象的最后一个引用被销毁时才会销毁它。如果上面显示的是john的情况,如果其他东西保留在指向它的智能指针上,则孩子可能“幸存”其所有父母。如果您的目的是让Child只属于一个Parent并且使用它的Parent进行破坏,那么您应该将Parent创建逻辑封装在Parent中,这样Child对象只能由Parent对象创建。