ReadingLab / Discussion-for-Cpp

C++ 中文讨论区
MIT License
88 stars 63 forks source link

对于ex13_8编写赋值运算符为何不直接对指针指向的值赋值? #68

Closed southmountain closed 8 years ago

southmountain commented 8 years ago

参考答案 HasPtr& operator=(const HasPtr& hp) { std::string* new_ps = new std::string(hp.ps); delete ps; ps = new_ps; i = hp.i; return this; } 为什么不直接对 ps 赋值,而是要先delete ps,释放掉它的内存空间,再重新申请空间赋值? HasPtr&operator=(const HasPtr &hp){ ps = hp.ps; i = hp.i; return this; }

pezy commented 8 years ago

为什么不直接对 *ps 赋值,而是要先delete ps,释放掉它的内存空间,再重新申请空间赋值?

首先, 完全可以直接赋值, 因为*psstd::string 类型.

然后, 为什么这里写的如此啰嗦?

直接原因是: 为了和书上的例子保持一致, 请见: 13.2.1 小节 Valuelike Copy-Assignment Operator 的例子.

根本原因是: 这个 HasPtr 的例子是这本书的一个瑕疵. 因为 ps 这个成员弄成 string* 非常莫名其妙. 完全可以直接用 std::string, 从而避免用指针.(也就避免了内存的管理)

试想, 如果有一个成员是 int *, 然后构造函数里会 new 一个 int 型的数组. 那么它的拷贝构造, 和拷贝赋值会怎么写?


std::string* new_ps = new std::string(*hp.ps);
delete ps;
ps = new_ps;

这三步, 诠释的是一种通用的解决方案. 即先 new 出一个新临时资源, 然后析构原始资源, 最后将原始指针指向新的临时资源.

对这三步进一步的优化, 应该是著名的 Copy-and-swap idiom.

对于该技巧的更多阐述请见: http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom

回到原来的问题, 如果先忽略 std::string 的特殊性, 结合Valuelike Copy-Assignment Operator 的知识, 考虑为什么这样分三步写, 能更加安全和清晰.

最终会考虑为何要引入 swap 函数.

这就像一条隐隐的脉络, 让你更了解 C++ 的一些 trick 的深层原因.

本答案和书一样, 目的都是引导新手考虑语言的问题, 而并非是引导工程实践上的"优化".

southmountain commented 8 years ago

多谢