• Qt中对象树的机制介绍以及底层实现,各种结果分析:(以及自己写容易犯错的点)


    1对象树机制:

    在创建QObject对象的时候,可以提供一个父对象,我们创建的这个QObject对象的时候会自动添加到其父对象的children()列表。当父对象析构的时候,这个列表的所有对象都会被析构。

    2Qt中高效且简易的内存回收机制的源码剖析及底层实现:

    1. #include
    2. #include
    3. using namespace std;
    4. class Object;
    5. typedef list Children;
    6. class Object
    7. {
    8. public:
    9. Children children;
    10. Object(Object* parent=nullptr)
    11. {
    12. if(parent!=nullptr){
    13. parent->children.push_back(this);
    14. }
    15. }
    16. virtual ~Object()
    17. {
    18. for(auto it=children.begin();it!=children.end();it++){
    19. delete *it;
    20. }
    21. }
    22. };
    23. class A:public Object
    24. {
    25. public:
    26. A(Object* parent=nullptr)
    27. {
    28. if(parent!=nullptr){
    29. parent->children.push_back(this);
    30. }
    31. cout<<"A的构造"<
    32. }
    33. ~A()
    34. {
    35. cout<<"A的析构"<
    36. }
    37. };
    38. int main()
    39. {
    40. Object obj;
    41. A* a=new A(&obj);
    42. return 0;
    43. }

    3.自己写的时候注意点:

    3.1父类中的析构一定要加virtual形成多态,不然即使A中的地址是被释放了,但是释放的类型是Object的类型,并不会条用A中的析构,这样就很危险,如果当A中有一个指针的时候,就没法释放,造成内存泄漏,而且此时因为a的地址已经被隐式强转了,所以再次删除删除的是Object类型,所以Object类型会被调用两次析构。

    1. #include
    2. #include
    3. using namespace std;
    4. class Object;
    5. typedef list Children;
    6. class Object
    7. {
    8. public:
    9. Children children;
    10. Object(Object* parent=nullptr)
    11. {
    12. if(parent!=nullptr){
    13. parent->children.push_back(this);
    14. }
    15. }
    16. ~Object()
    17. {
    18. for(auto it=children.begin();it!=children.end();it++){
    19. delete *it;
    20. *it=nullptr;
    21. }
    22. cout<<"Object的析构"<
    23. }
    24. };
    25. class A:public Object
    26. {
    27. public:
    28. A(Object* parent=nullptr)
    29. {
    30. if(parent!=nullptr){
    31. parent->children.push_back(this);
    32. }
    33. cout<<"A的构造"<
    34. }
    35. ~A()
    36. {
    37. cout<<"A的析构"<
    38. }
    39. };
    40. int main()
    41. {
    42. Object obj(nullptr);
    43. A* a=new A(&obj);
    44. return 0;
    45. }

    结果图:

    3.2这是我当时自己犯的错误,代码如下:

    1. #include
    2. #include
    3. using namespace std;
    4. class Object;
    5. typedef list Children;
    6. class Object
    7. {
    8. public:
    9. Children children;
    10. Object(Object* parent)
    11. {
    12. if(parent!=nullptr){
    13. parent->children.push_back(this);
    14. }
    15. }
    16. virtual ~Object()
    17. {
    18. for(auto it=children.begin();it!=children.end();it++){
    19. delete *it;
    20. *it=nullptr;
    21. }
    22. cout<<"Object的析构"<
    23. }
    24. };
    25. class A:public Object
    26. {
    27. public:
    28. A(Object* parent=nullptr):Object(parent)
    29. {
    30. if(parent!=nullptr){
    31. parent->children.push_back(this);
    32. }
    33. cout<<"A的构造"<
    34. }
    35. ~A()
    36. {
    37. cout<<"A的析构"<
    38. }
    39. };
    40. int main()
    41. {
    42. Object obj(nullptr);
    43. A* a=new A(&obj);
    44. return 0;
    45. }

    结果图:

    3.2.1分析: 

     如图所示:当父类调用过一次后,删除了Object的类型的a的地址,按照我们上面的理解一个还会再调用一次析构,但是当析构过一次后,它直接报错了,这是为什么呢?当我们 在A中进行初始化的时候,如果按照开头我们写的那种正确方法,其实是给parent初始化为nullptr,但是当我们3.2这种写法的时候,初始化的并不是nullptr,而是a的地址,所以我们在父类中也将a中的地址放进了list中,在A中也将a的地址放进了list中,所以在条用父类中的析构的时候,我们释放了两次一模一样的地址,所以肯定会报错。

  • 相关阅读:
    使用WIX 进行商业智能OEM打包
    squid代理服务器(传统代理、透明代理、反向代理、ACL、日志分析)
    Kubernetes CRD 介绍
    Aragon创建DAO polygon BSC测试网
    【C++】继承和多态常见的问题
    【无标题】
    牛客网SQL160
    文本分类微调技巧实战2.0
    杭电oj 2059 龟兔赛跑 C语言
    力扣第541题 反转字符串 II c++注释 双指针基础版
  • 原文地址:https://blog.csdn.net/a2998658795/article/details/126146605