C++11 中的移动语义
Move semantics in C++11
我想完全理解 C++11 中的移动语义。所以我写了几个 类 来查看何时调用不同的构造函数:
#include <iostream>
using namespace std;
class A {
public:
A() : a1_(0) {std::cout << "Calling constructor" << std::endl;}
A(A&& other) {
std::cout << "Calling move constructor" << std::endl;
a1_ = other.a1_;
other.a1_ = 0;
}
// Move assignment operator.
A& operator=(A&& other) {
std::cout << "Calling move operator" << std::endl;
if (this != &other) {
a1_ = other.a1_;
other.a1_ = 0;
}
return *this;
}
// Copy constructor.
A(const A& other) {
std::cout << "Calling copy constructor" << std::endl;
a1_ = other.a1_;
}
// Copy assignment operator.
A& operator=(const A& other) {
std::cout << "Calling copy assignment operator" << std::endl;
if (this != &other) {
a1_ = other.a1_;
}
return *this;
}
private:
int a1_;
};
class B {
A oA_;
public:
B() {}
void setoA(A a) {oA_ = a;}
A getoA() {return oA_;}
};
A createA() {
A a1;
return a1;
}
B createB() {
B tmpB;
A tmpA;
tmpB.setoA(tmpA);
return tmpB;
}
int main() {
B b;
A a;
b.setoA(a);
std::cout << "**************************" << std::endl;
b.setoA(createA());
std::cout << "**************************" << std::endl;
b.setoA(std::move(createA()));
std::cout << "**************************" << std::endl;
B b2;
b2.setoA(b.getoA());
std::cout << "**************************" << std::endl;
createB();
return 0;
}
当我检查这段代码的输出时:
Calling constructor
Calling constructor
Calling copy constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling move constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling copy constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling constructor
Calling copy constructor
Calling copy assignment operator
我这里有些疑惑:
我以为如果你传递r-value
,移动构造函数就会被调用,是吗?这 b.setoA(createA());
不是 r-value
吗?
我怎样才能让 constructor/operator 被跟注?
First of all in first section, why is constructor being called twice?
因为您构造了一个 B
和一个 A
,前者有自己的 A
实例,第一个(意外的)构造函数调用来自该实例。
I thought that if you pass r-value move constructor will be called, is that right? Isn't this b.setoA(createA());
an r-value?
从 createA
中调用构造函数(是的,return 值 是 r 值),但是,复制省略发生并且在setoA
.
的参数变量中直接实例化对象
然而,在 setoA
中,选择了复制赋值,因为现在 a
是一个左值。如果您想搬家,您需要:
void setoA(A a) { oA_ = std::move(a); }
编译器可能会选择性地省略某些副本和移动。为防止这种情况,请在 GCC 和 Clang 中使用 -fno-elide-constructors
。此外,一些移动省略在 C++17 中成为强制性的,因此要强制编译器使用 C++11 移动语义,请同时使用 -std=c++11
。
我想完全理解 C++11 中的移动语义。所以我写了几个 类 来查看何时调用不同的构造函数:
#include <iostream>
using namespace std;
class A {
public:
A() : a1_(0) {std::cout << "Calling constructor" << std::endl;}
A(A&& other) {
std::cout << "Calling move constructor" << std::endl;
a1_ = other.a1_;
other.a1_ = 0;
}
// Move assignment operator.
A& operator=(A&& other) {
std::cout << "Calling move operator" << std::endl;
if (this != &other) {
a1_ = other.a1_;
other.a1_ = 0;
}
return *this;
}
// Copy constructor.
A(const A& other) {
std::cout << "Calling copy constructor" << std::endl;
a1_ = other.a1_;
}
// Copy assignment operator.
A& operator=(const A& other) {
std::cout << "Calling copy assignment operator" << std::endl;
if (this != &other) {
a1_ = other.a1_;
}
return *this;
}
private:
int a1_;
};
class B {
A oA_;
public:
B() {}
void setoA(A a) {oA_ = a;}
A getoA() {return oA_;}
};
A createA() {
A a1;
return a1;
}
B createB() {
B tmpB;
A tmpA;
tmpB.setoA(tmpA);
return tmpB;
}
int main() {
B b;
A a;
b.setoA(a);
std::cout << "**************************" << std::endl;
b.setoA(createA());
std::cout << "**************************" << std::endl;
b.setoA(std::move(createA()));
std::cout << "**************************" << std::endl;
B b2;
b2.setoA(b.getoA());
std::cout << "**************************" << std::endl;
createB();
return 0;
}
当我检查这段代码的输出时:
Calling constructor Calling constructor Calling copy constructor Calling copy assignment operator ++++++++++++++++++++++++++++++++++ Calling constructor Calling copy assignment operator ++++++++++++++++++++++++++++++++++ Calling constructor Calling move constructor Calling copy assignment operator ++++++++++++++++++++++++++++++++++ Calling constructor Calling copy constructor Calling copy assignment operator ++++++++++++++++++++++++++++++++++ Calling constructor Calling constructor Calling copy constructor Calling copy assignment operator
我这里有些疑惑:
我以为如果你传递r-value
,移动构造函数就会被调用,是吗?这 b.setoA(createA());
不是 r-value
吗?
我怎样才能让 constructor/operator 被跟注?
First of all in first section, why is constructor being called twice?
因为您构造了一个 B
和一个 A
,前者有自己的 A
实例,第一个(意外的)构造函数调用来自该实例。
I thought that if you pass r-value move constructor will be called, is that right? Isn't this
b.setoA(createA());
an r-value?
从 createA
中调用构造函数(是的,return 值 是 r 值),但是,复制省略发生并且在setoA
.
在 setoA
中,选择了复制赋值,因为现在 a
是一个左值。如果您想搬家,您需要:
void setoA(A a) { oA_ = std::move(a); }
编译器可能会选择性地省略某些副本和移动。为防止这种情况,请在 GCC 和 Clang 中使用 -fno-elide-constructors
。此外,一些移动省略在 C++17 中成为强制性的,因此要强制编译器使用 C++11 移动语义,请同时使用 -std=c++11
。