现在已经回答了:不要费心阅读这个问题,它有点冗长,可能不值得你花时间。我的代码中存在错误,这就是未调用移动构造函数的原因。检查答案以获取详细信息。请记住,RVO 和 NRVO(命名返回值优化)可能会导致调用未按预期发生。
我希望为这一行调用 move ctor,但调用的是 copy ctor:
Ding d3 = d1 + d2;
Ding 类有一个用户定义的 move ctor 和 operator+ 重载。我希望调用移动 ctor 的原因是 operator+ 返回一个临时对象,一个右值引用,因此可能会发生移动优化。
我在这里写的所有内容都可能是错误的,因为我是 C++ 初学者。这是代码:
// Copied and modified code from here: https://stackoverflow.com/a/3109981
#include <iostream>
#include <cstring>
struct Ding {
char* data;
Ding(const char* p) {
std::cout << " ctor for: " << p << "\n";
size_t size = strlen(p) + 1;
data = new char[size];
memcpy(data, p, size);
}
~Ding() {
std::cout << " dtor for: " << data << "\n";
delete[] data;
}
Ding(const Ding& that) {
std::cout << " copy for: " << that.data << "\n";
size_t size = strlen(that.data) + 1;
data = new char[size];
memcpy(data, that.data, size);
}
Ding(Ding&& that) {
std::cout << " MOVE for: " << that.data << "\n";
data = that.data;
that.data = nullptr;
}
Ding& operator=(Ding that) {
std::cout << " assignment: " << that.data << "\n";
std::swap(data, that.data);
return *this;
}
Ding& operator+(const Ding that) const {
std::cout << " plus for: " << that.data << "\n";
size_t len_this = strlen(this->data);
size_t len_that = strlen(that.data);
char * tmp = new char[len_this + len_that + 1];
memcpy( tmp, this->data, len_this);
memcpy(&tmp[len_this], that.data, len_that + 1);
Ding * neu = new Ding(tmp);
return *neu;
}
};
void print(Ding d) {
std::cout << " (print): " << d.data << std::endl;
}
int main(void) {
std::cout << "putting a Ding on the stack\n";
Ding d1("jajaja");
std::cout << "calling print routine\n";
print(d1);
std::cout << "putting a second Ding on the stack\n";
Ding d2("nein");
// std::cout << "calling print routine\n";
// print(d2);
std::cout << "Putting a third Ding on the stack, init from + op ...\n";
std::cout << "... so expecting so see MOVE ctor used ...\n";
Ding d3 = d1 + d2;
// std::cout << "calling print routine\n";
// print(d3);
std::cout << "End of main, dtors being called ...\n";
}
VC2010 Express 和 MinGW (GCC 4.6) 的编译器调用(在 Win7 上)如下:
cl /nologo /W4 /EHsc /MD move-sem.cpp
g++ -std=c++0x move-sem.cpp -o move-gcc.exe
两个二进制文件产生相同的输出(程序结束时没有破坏顺序):
putting a Ding on the stack
ctor for: jajaja
calling print routine
copy for: jajaja
(print): jajaja
dtor for: jajaja
putting a second Ding on the stack
ctor for: nein
Putting a third Ding on the stack, init from + op ...
... so expecting so see MOVE ctor used ...
copy for: nein
plus for: nein
ctor for: jajajanein
dtor for: nein
copy for: jajajanein
End of main, dtors being called ...
dtor for: jajajanein
dtor for: nein
dtor for: jajaja
回想一下这个长文本之后的问题:为什么不调用移动构造函数Ding d3 = d1 + d2;
?
我知道还有其他关于为什么没有调用移动 ctor 的问题,但我无法将他们的答案映射到这个案例。
更新
根据 David Rodriguez 的评论,我将程序更改如下:
--- move-sem.cpp.orig 2012-03-17 17:00:56.901570900 +0100
+++ move-sem.cpp 2012-03-17 17:01:14.016549800 +0100
@@ -36,15 +36,14 @@
return *this;
}
- Ding& operator+(const Ding that) const {
+ Ding operator+(const Ding that) const {
std::cout << " plus for: " << that.data << "\n";
size_t len_this = strlen(this->data);
size_t len_that = strlen(that.data);
char * tmp = new char[len_this + len_that + 1];
memcpy( tmp, this->data, len_this);
memcpy(&tmp[len_this], that.data, len_that + 1);
- Ding * neu = new Ding(tmp);
- return *neu;
+ return tmp;
}
};
然后,我使用上面提到的编译器调用重新编译了程序,并得到了一个输出,其中copy for: jajajanein
删除了一个副本 ( )。然后我尝试了以下行:
g++ -std=c++0x -fno-elide-constructors move-sem.cpp -o move-gcc.exe
还有塔塔!现在我看到了移动 ctor 在工作!...但是我认为现在还有另一个错误,该 new 的输出move-gcc.exe
不再列出 dtor 调用:
putting a Ding on the stack
ctor for: jajaja
calling print routine
copy for: jajaja
(print): jajaja
dtor for: jajaja
putting a second Ding on the stack
ctor for: nein
Putting a third Ding on the stack, init from + op ...
... so expecting so see MOVE ctor used ...
copy for: nein
plus for: nein
ctor for: jajajanein
MOVE for: jajajanein
dtor for:
第二次更新
我用operator+
以下(可能同样糟糕)代码替换了坏的:
Ding& operator+=(const Ding & rhs) {
std::cout << " op+= for: " << data << " and " << rhs.data << "\n";
size_t len_this = strlen(this->data);
size_t len_that = strlen(rhs.data);
char * buf = new char[len_this + len_that + 1];
memcpy( buf, this->data, len_this);
memcpy(&buf[len_this], rhs.data, len_that + 1);
delete[] data;
data = buf;
return *this;
}
Ding operator+(const Ding & rhs) const {
Ding temp(*this);
temp += rhs;
return temp;
}
我还从析构函数中删除了以下行,它阻止了程序异常终止:
std::cout << " dtor for: " << data << "\n";
使用 MSVC 和g++ -std=c++0x -fno-elide-constructors
.