【发布时间】:2019-03-17 20:58:19
【问题描述】:
这个问题不同于所有的:
extraneous calls to copy-constructor and destructor(相关但在我的案例中未使用 STL)
[为什么类的析构函数被调用了两次?] (Why is the destructor of the class called twice?)(无关)
堆栈溢出建议。
假设你有这个简单的代码。
#include <iostream>
using namespace std;
class Int {
private:
int i_;
public:
Int(Int &&obj) : i_(obj.i_) { //move constructor
print_address_change_(&obj);
cout << i_ << " moved.\n";
}
Int(const Int &obj) : i_(obj.i_) { //copy constructor
print_address_change_(&obj);
cout << i_ << " copied.\n";
}
Int(int i) : i_(i) {
print_address_();
cout << i_ << " constructed.\n";
}
~Int() {
print_address_();
cout << i_ << " destructed.\n";
}
void print_address_() const {
cout << "(" << this << ") ";
}
void print_address_change_(const Int *p) const {
cout << "(" << p << " -> " << this << ") ";
}
const Int operator * (const Int &rhs) const {
return Int(i_ * rhs.i_);
}
};
int main() {
Int i(3);
Int j(8);
cout << "---\n";
Int k = i * j;
cout << "---\n";
}
结果(由 g++ 7.3.0 使用默认选项)是这个。
(0x7ffd8e8d11bc) 3 constructed. //i
(0x7ffd8e8d11c0) 8 constructed. //j
---
(0x7ffd8e8d11c4) 24 constructed. //tmp
---
(0x7ffd8e8d11c4) 24 destructed. //k
(0x7ffd8e8d11c0) 8 destructed. //j
(0x7ffd8e8d11bc) 3 destructed. //i
好的。有点奇怪,但你可以说copy elision 一定发生了。所以现在使用-fno-elide-constructors 选项,您会得到以下结果。
(0x7ffd8f7693f8) 3 constructed. //i
(0x7ffd8f7693fc) 8 constructed. //j
---
(0x7ffd8f7693c4) 24 constructed. //tmp
(0x7ffd8f7693c4 -> 0x7ffd8f769404) 24 moved. //tmp -> ??? (WHY?)
(0x7ffd8f7693c4) 24 destructed. //tmp
(0x7ffd8f769404 -> 0x7ffd8f769400) 24 copied. //??? -> k (WHY?)
(0x7ffd8f769404) 24 destructed. //??? (WHY?)
---
(0x7ffd8f769400) 24 destructed. //k
(0x7ffd8f7693fc) 8 destructed. //j
(0x7ffd8f7693f8) 3 destructed. //i
这比我预期的多出三行(标记为“WHY”)。 ??? 是什么?谁能告诉我那里发生了什么?
【问题讨论】:
-
移动构造以移动返回值,以及
k的复制构造。使用调试器单步执行代码应该可以确认这一点。请记住,复制省略已关闭。 -
从
operator*返回一个const Int似乎很奇怪。这是您获得副本而不是第二步的原因。 -
当你返回没有复制省略的东西时,它必须被复制/移动到一个临时对象。您使用
Int(i_ * rhs.i_)创建一个临时文件,然后在您返回它时将其移至另一个临时文件。 -
@HolyBlackCat 谢谢。我现在明白了。
-
@super 是这样吗?这个实现是(编辑的)Effective C++ 3rd Edition 的摘录。您可以从GoogleBooks查看相关页面。我想知道是否有更好的实现。
标签: c++