【发布时间】:2019-10-02 08:14:26
【问题描述】:
我通过定义默认、复制和移动构造函数来创建一个类字符串。我尝试创建期望调用每个构造函数的对象。正如预期的那样,调用了默认和复制构造函数,但是当我传递一个右值(临时对象)时,我仍然看到移动构造函数没有被调用。
#include <iostream>
#include <cstdlib>
#include <cstring>
class string
{
char * data;
public:
string(const char * p = nullptr)
{
if(p == nullptr) return;
std::cout << "string(const char * p)" << std::endl;
size_t size = strlen(p) + 1;
data = new char[size];
memcpy(data, p, size);
}
~string()
{
std::cout << "~string() - " << data << std::endl;
delete[] data;
}
string(const string & that)
{
std::cout << "string(const string &)" << std::endl;
size_t size = strlen(that.data) + 1;
data = new char[size];
memcpy(data, that.data, size);
}
string(string && that)
{
std::cout << "string(string && )" << std::endl;
data = that.data;
that.data = nullptr;
}
void showData() { std::cout << data << std::endl; }
string operator+(const string & other)
{
size_t datasize = strlen(data);
size_t othersize = strlen(other.data);
size_t totalsize = datasize + othersize + 1;
char * sData = new char[totalsize];
memcpy(sData, data, strlen(data));
memcpy(sData+datasize, other.data, totalsize-datasize);
string s(sData);
delete[] sData;
return s;
}
string & operator=(string that)
{
char * tmp = data;
data = that.data;
that.data = tmp;
return *this;
}
};
int main()
{
string s1{"stackoverflow"}; // s1
string s2{s1}; // s2
string s3{string("stack")+string("exchange")}; // s3
}
在 s1:默认构造函数正在按预期调用。
在s2:复制构造函数被调用,也如预期的那样。
在 s3:我正在传递一个临时对象。所以,我希望 move 构造函数 被调用,但是 default 构造函数 被调用。
我无法理解我错过了什么。请帮忙,谢谢。
【问题讨论】:
-
哪个编译器?我看到它被调用了,但怀疑是 UB
-
使用 gcc HEAD 10.0.0 20190 和 clang HEAD 9.0.0 从 wandbox.org 编译。
-
这里
string s3{string("stack")+string("exchange")}; // s3默认构造函数被调用了 3 次:string("stack")、string("exchange")和operator+中的string s(sData)行。正如doctorlove所提到的,由于UB,移动构造函数还没有被执行 -
s3是允许编译器省略移动构造函数(和一个匹配的析构函数)的情况。搜索“C++ 复制省略”有几篇解释的文章。 -
与问题无关:如果参数为空指针,默认构造函数需要将
data设置为nullptr。
标签: c++ c++11 move move-semantics move-constructor