• C++11 指针成员与拷贝构造(浅拷贝与深拷贝)


    【1】浅拷贝

    一直以来,设计一个类,个人认为,最能体现水平的地方在于:类中含有指针成员变量。

    如下一个典型的浅拷贝示例:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 class HasPtrMem
     5 { 
     6 public:
     7     HasPtrMem() : d(new int(0))
     8     {} 
     9     ~HasPtrMem() 
    10     { 
    11         delete d;
    12         d = nullptr;
    13     }
    14     
    15     int* d;
    16 }; 
    17 
    18 int main()
    19 { 
    20     HasPtrMem a; 
    21     HasPtrMem b(a); 
    22     
    23     cout << *a.d << endl; // 0
    24     cout << *b.d << endl; // 0
    25 } // 异常析构

    定义了一个含有指针成员变量d的类型HasPtrMem。

    该成员d在构造时会接受一个new操作分配堆内存返回的指针,而在析构的时候则会被delete操作用于释放分配的堆内存。

    在main函数中,声明了HasPtrMem类型的对象a,又使用a初始化了对象b。按照C++的语法,这会调用HasPtrMem的拷贝构造函数。

    而这里的拷贝构造函数由编译器隐式生成,其作用是执行类似于memcpy的按位拷贝。

    这样的构造方式有一个问题,就是a.d和b.d都指向了同一块堆内存。

    因此在main作用域结束的时候,对象b和对象a的析构函数会分别依次被调用。

    当其中之一完成析构之后(比如对象b先析构,b.d先被delete),那么a.d就成了一个“悬挂指针”(dangling pointer),因为其不再指向有效的内存了。

    那么在该悬挂指针上释放内存就会造成严重的错误。

    【2】深拷贝

    通常情况下,在类中未声明构造函数的情况下,C++也会为类生成一个“浅拷贝”(shollow copy)的构造函数。

    而最佳的解决方案是用户自定义拷贝构造函数来实现“深拷贝”(deep copy),修正上例为深拷贝的结果:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 class HasPtrMem
     5 { 
     6 public:
     7     HasPtrMem() : d(new int(0))
     8     {}
     9     HasPtrMem(const HasPtrMem& h) : d(new int(*h.d)) { } // 拷贝构造函数,从堆中分配内存,并用*h.d初始化
    10     ~HasPtrMem() 
    11     { 
    12         delete d;
    13         d = nullptr;
    14     }
    15     
    16     int* d;
    17 }; 
    18 
    19 int main()
    20 { 
    21     HasPtrMem a; 
    22     HasPtrMem b(a); 
    23     
    24     cout << *a.d << endl; // 0
    25     cout << *b.d << endl; // 0
    26 } // 正常析构

    为类HasPtrMem添加了一个拷贝构造函数。

    拷贝构造函数从堆中分配新内存,将该分配来的内存的指针交还给d,又使用*(h.d)对*d进行了初始化。

    通过这样的方法,就避免了悬挂指针的困扰。

    good good study, day day up.

    顺序 选择 循环 总结

  • 相关阅读:
    Silverlight 调用GP服务第一篇之发布GP服务(Geoprocessing Service)
    SQLServer中char、varchar、nchar、nvarchar的区别:
    word中带圈符号如何手动输入
    js中循环for
    正则表达式总结
    SQL Server 2008 数据库 不允许保存修改。
    多线程三种锁Monitor,lock,Mutex
    Lambda和Linq的用法
    RowDeleting和RowDeleted区别
    ASP.NET中aspx.cs页面代码中的换行方法
  • 原文地址:https://www.cnblogs.com/Braveliu/p/12233571.html
Copyright © 2020-2023  润新知