C++;11移动语义 我试图理解C++ 11如何移动语义。我实现了一个类,该类将指针包装到字符串对象,但没有按预期调用move构造函数或move赋值运算符
我通过EclipseCDT使用GCC4.7.2: 你能帮我理解原因吗C++;11移动语义 我试图理解C++ 11如何移动语义。我实现了一个类,该类将指针包装到字符串对象,但没有按预期调用move构造函数或move赋值运算符,c++,c++11,constructor,variable-assignment,move-semantics,C++,C++11,Constructor,Variable Assignment,Move Semantics,我通过EclipseCDT使用GCC4.7.2: 你能帮我理解原因吗 #include <iostream> #include <string> #include <utility> using namespace std; class StringPointerWrapper { public: // Default constructor with default value StringPointerWrapper(const st
#include <iostream>
#include <string>
#include <utility>
using namespace std;
class StringPointerWrapper {
public:
// Default constructor with default value
StringPointerWrapper(const std::string& s = "Empty"): ps(new std::string(s)) {
std::cout << "Default constructor: " << *ps << std::endl;
}
//Copy constructor
StringPointerWrapper(const StringPointerWrapper& other): ps(new std::string(*other.ps)) {
std::cout << "Copy constructor: " << *other.ps << std::endl;
}
//Copy assignment operator
StringPointerWrapper& operator=(StringPointerWrapper other) {
std::cout << "Assignment operator (ref): " << *other.ps << std::endl;
swap(ps, other.ps);
return *this;
}
//Alternate copy assignment operator
/*StringPointerWrapper& operator=(StringPointerWrapper& other) {
std::cout << "Assignment operator (val)" << std::endl;
//We need to do the copy by ourself
StringPointerWrapper temp(other);
swap(ps, temp.ps);
return *this;
}*/
//Move constructor
StringPointerWrapper(StringPointerWrapper&& other) noexcept : ps(nullptr) {
std::cout << "Move constructor: " << *other.ps << std::endl;
ps = other.ps;
other.ps = nullptr;
}
//Move assignment operator
StringPointerWrapper& operator= (StringPointerWrapper&& other) noexcept {
std::cout << "Move assignment operator: " << *other.ps << std::endl;
if(this != &other) {
delete ps;
ps = other.ps;
other.ps = nullptr;
}
return *this;
}
//Destructor
~StringPointerWrapper() {
std::cout << "Destroying: " << *this << std::endl;
delete ps;
}
private:
friend std::ostream& operator<<(std::ostream& os, StringPointerWrapper& spw) {
os << *spw.ps;
return os;
}
std::string *ps;
};
int main(int argc, char *argv[]) {
StringPointerWrapper spw1("This is a string");
StringPointerWrapper spw2;
StringPointerWrapper spw3("This is another string");
StringPointerWrapper spw4 = {"This is a const string"};
StringPointerWrapper spw5(StringPointerWrapper("String for move constructor"));
std::cout << "spw2 before: " << spw2 << std::endl;
spw2 = spw3;
std::cout << "spw2 after: " << spw2 << std::endl;
StringPointerWrapper spw6 = StringPointerWrapper("String for move assignment");
std::cout << spw1 << std::endl;
std::cout << spw2 << std::endl;
std::cout << spw3 << std::endl;
std::cout << spw4 << std::endl;
std::cout << spw5 << std::endl;
std::cout << spw6 << std::endl;
}
#包括
#包括
#包括
使用名称空间std;
类StringPointerRapper{
公众:
//具有默认值的默认构造函数
StringPointerRapper(const std::string&s=“Empty”):ps(新std::string){
std::cout您需要告诉编译器自己使用std::move移动对象
尝试:
您需要告诉编译器自己使用std::move移动对象
尝试:
未调用移动构造函数,因为编译器正在将构造函数作为优化省略。如果在编译器调用中传递-fno elide构造函数
,则可以禁用此操作
但是,您会遇到问题,因为您的移动构造函数只是使用了other
中的指针,该指针很快就会被删除。将std::string
作为指针保存实际上没有意义,您应该直接将其保存,然后在移动赋值操作符和移动构造函数中调用std::move
。未调用ove构造函数,因为编译器正在将该构造函数作为优化进行省略。如果在编译器调用中传递-fno elide构造函数
,则可以禁用此功能
但是,您会遇到问题,因为您的移动构造函数只是使用了other
中的指针,该指针很快就会被删除。将std::string
作为指针保存实际上没有意义,您应该直接将其保存,然后在移动赋值运算符和移动构造函数中调用std::move
StringPointerRapper spw5(StringPointerRapper(“移动构造函数的字符串”)
这将调用默认构造函数,因为编译器已决定通过不创建临时(即,它已决定执行StringPointerRapper spw5(“移动构造函数的字符串”)
)对其进行优化。相反,通过执行StringPointerRapper spw5(std::move(StringPointerRapper(“移动构造函数的字符串”))强制移动;
StringPointerRapper spw6=StringPointerRapper(“移动分配字符串”)
同样,编译器通过优化临时构造函数的创建来调用默认构造函数
注意:您的操作员
StringPointerRapper spw5(StringPointerRapper(“移动构造函数的字符串”)
这将调用默认构造函数,因为编译器已决定通过不创建临时(即,它已决定执行StringPointerRapper spw5(“移动构造函数的字符串”)
)对其进行优化。相反,通过执行StringPointerRapper spw5(std::move(StringPointerRapper(“移动构造函数的字符串”))强制移动;
StringPointerRapper spw6=StringPointerRapper(“移动分配字符串”)
同样,编译器通过优化临时构造函数的创建来调用默认构造函数
注意:您的运算符之前,这可能不是理解移动语义的最佳示例。std::string
基本上是一个围绕char*
的包装器,因此您正在围绕指向char数组指针的包装器构建一个包装器。您能给出输出吗?输出是:Default constructor:这是一个字符串默认构造函数:空默认构造函数:这是另一个字符串默认构造函数:这是一个常量字符串默认构造函数:移动构造函数spw2之前的字符串:空复制构造函数:这是另一个字符串赋值运算符(ref):这是另一个字符串销毁:空spw2 after:这是另一个字符串默认构造函数:移动赋值字符串这是另一个字符串这是另一个字符串这是移动构造函数的常量字符串移动赋值字符串所有析构函数调用之前,这可能不是最好的示例站立移动语义。std::string
基本上是一个围绕char*
的包装器,因此您正在围绕指向char数组的指针的包装器构建一个包装器。您可以给出输出吗?输出是:默认构造函数:这是一个字符串默认构造函数:空默认构造函数:这是另一个字符串默认构造函数构造函数:这是一个常量字符串默认构造函数:移动构造函数spw2之前的字符串:空复制构造函数:这是另一个字符串赋值运算符(ref):这是另一个字符串销毁:空spw2 after:这是另一个字符串默认构造函数:移动分配字符串这是另一个字符串这是另一个字符串这是移动构造函数字符串这是移动分配构造函数字符串所有析构函数调用我感谢您的回答。应用建议的更改程序崩溃。:(编译器决定移动什么。它移动r值。std::move
基本上将l值转换为r值,这样移动语义就可以生效。std::move
不会移动(相当糟糕的名称…)无论如何,我的期望是StringPointerRapper的返回值(“移动构造函数的字符串”))是一个非保留值引用。因此,它应该绑定到复制构造函数和移动构造函数。无论如何,复制构造函数有一个常量左值引用(const stringpointerrapper&other)因此,重载解析应该选择具有非常量右值引用的move构造函数(StringPointerRapper&&other).我错了吗?@salvo崩溃前控制台打印什么?崩溃前的输出是:默认构造函数:这是一个字符串默认构造函数:空默认构造函数:这是另一个字符串默认构造函数c
StringPointerWrapper spw5(std::move(StringPointerWrapper("String for move constructor")));
friend std::ostream& operator<<(std::ostream& os, StringPointerWrapper& spw) {
if (spw.ps)
os << (spw.ps);
else
os << "null";
return os;
}