C++11指针成员与拷贝构造(浅拷贝与深拷贝)
【1】浅拷贝
⼀直以来,设计⼀个类,个⼈认为,最能体现⽔平的地⽅在于:类中含有指针成员变量。
如下⼀个典型的浅拷贝⽰例:
1 #include <iostream>
2using namespace std;
3
4class HasPtrMem
5 {
6public:
7 HasPtrMem() : d(new int(0))
8 {}
9 ~HasPtrMem()
10 {
11delete d;
12 d = nullptr;
13 }
14
15int* d;
16 };
17
18int 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>
2using namespace std;
3
4class HasPtrMem
5 {
6public:
7 HasPtrMem() : d(new int(0))
8 {}
9 HasPtrMem(const HasPtrMem& h) : d(new int(*h.d)) { } //拷贝构造函数,从堆中分配内存,并⽤*h.d初始化
10 ~HasPtrMem()
11 {
12delete d;
13 d = nullptr;
14 }指针调用成员函数
15
16int* d;
17 };
18
19int 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.
顺序选择循环总结
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论