C++11移动语义
C++ 11 Move Semantics
我正在努力理解C++11移动语义是如何工作的。我已经实现了一个类,它封装了一个指向String对象的指针,但移动构造函数和移动赋值运算符都没有按预期调用。
我通过Eclipse CDT:使用GCC 4.7.2
你能帮我理解原因吗?
#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;
}
move构造函数没有被调用,因为编译器将省略构造函数作为优化。如果在编译器调用中传递-fno-elide-constructors
,则可以禁用它。
但是,您会遇到问题,因为您的move构造函数只是使用other
中的指针,该指针很快就会被删除。将std::string
作为指针是没有意义的,您应该直接持有它,并在移动赋值运算符和移动构造函数中调用std::move
。
StringPointerWrapper spw5(StringPointerWrapper("移动构造函数的字符串"));
这会调用默认构造函数,因为编译器决定通过不创建临时构造函数来优化它(即,它决定执行StringPointerWrapper spw5("String for move constructor")
)。相反,通过执行StringPointerWrapper spw5(std::move(StringPointerWrapper("String for move constructor")));
来强制移动。
StringPointerWrapper spw6=StringPointerWrapper("用于移动赋值的字符串");
同样,编译器通过优化临时构造函数的创建来调用默认构造函数。
注意:您的operator<<
需要防范空指针。例如,
friend std::ostream& operator<<(std::ostream& os, StringPointerWrapper& spw) {
if (spw.ps)
os << (spw.ps);
else
os << "null";
return os;
}
您需要告诉编译器自己使用std::move 移动东西
尝试:
StringPointerWrapper spw5(std::move(StringPointerWrapper("String for move constructor")));
- 何时在引用或唯一指针上使用移动语义
- 如何从具有移动语义的类对象中生成共享指针
- 可以使用移动语义更改或改进此C++代码吗?
- c++在使用指针时移动语义
- 使用移动和复制语义时函数匹配如何工作?
- 移动语义和深层/浅层复制之间有什么关系?
- 了解构造函数在移动、复制、赋值语义中的行为
- std::unique_lock移动语义
- 移动语义和运算符 + 重载
- C++ 移动语义是否在任何情况下都能节省资源?
- 移动语义在这里如何工作?
- 使用移动语义:右值引用作为方法参数
- 在C++中使用移动语义的正确方法是什么?
- 移动语义 c++ 单链表
- C++:使用整数移动语义
- 当变量和参数名称匹配时,移动语义构造失败
- 在 C++11 中移动语义
- 方法冗余移动调用的移动语义
- 视觉理解移动C++标准的语义
- 如何通过move语义移动多个参数