如果我有一个像这样的 C
类:
class C {
std::string s;
public:
C(std::string& s) : s(s) {}
C(std::string&& s) : C(s) {}
};
我是否通过从 string&&
构造函数调用 string&
构造函数来丢弃 move 语义?
最佳答案
是的,您正在抛弃您的 move 语义。我可以提供的最直接的方法是通过示例来演示。这是我能想到的最明智的事情,所以我希望清楚发生了什么。
考虑一下:
#include <iostream>
struct S
{
int x;
S() :x(1) { std::cout << __PRETTY_FUNCTION__ << '\n';}
S(const S& s) : x(s.x) { std::cout << __PRETTY_FUNCTION__ << '\n';}
S(S&& s) : x(std::move(s.x)) { ++x, s.x=0; std::cout << __PRETTY_FUNCTION__ << '\n';}
~S() { std::cout << __PRETTY_FUNCTION__ << ':' << x << '\n';}
};
class C {
S s;
public:
C(S& s) : s(s) { std::cout << __PRETTY_FUNCTION__ << '\n';}
C(S&& s) : C(s) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
~C() { std::cout << __PRETTY_FUNCTION__ << '\n';}
};
int main()
{
C c{S{}};
}
输出
S::S()
S::S(const S &)
C::C(S &)
C::C(S &&)
S::~S():1
C::~C()
S::~S():1
请注意,S
的两个 实例是通过 move 构造的,都不是。任何“move ”到预期目标的 S
都会为 x
打印 0
。没有。第一个 S
是 S{}
的初始临时值;第二个是通过 C(C&&)
初始化列表调用 C(C&)
生成的拷贝。这段代码完成后,当我们开始沿着析构函数链向下运行时,两个完全构造的 S
已经存在。
现在看看这个,相同的代码,但在 s
成员上使用了 move 语义:
#include <iostream>
struct S
{
int x;
S() :x(1) { std::cout << __PRETTY_FUNCTION__ << '\n';}
S(const S& s) : x(s.x) { std::cout << __PRETTY_FUNCTION__ << '\n';}
S(S&& s) : x(std::move(s.x)) { ++x, s.x=0; std::cout << __PRETTY_FUNCTION__ << '\n';}
~S() { std::cout << __PRETTY_FUNCTION__ << ':' << x << '\n';}
};
class C {
S s;
public:
C(S& s) : s(s) { std::cout << __PRETTY_FUNCTION__ << '\n';}
C(S&& s) : s(std::move(s)) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
~C() { std::cout << __PRETTY_FUNCTION__ << '\n';}
};
int main()
{
C c{S{}};
}
输出
S::S()
S::S(S &&)
C::C(S &&)
S::~S():0
C::~C()
S::~S():2
S
的两个实例仍然被构造,但后者是通过 move 构造,吸收第一个这样做。当我们开始销毁所有这些东西时,只有一个 S
实例仍然有效;另一个因搬家而死亡。
长话短说,如果你的目标在 move ,你就是在开枪。我希望有帮助,但如果没有帮助,我完全愿意扔掉它。
关于c++ - move 构造函数的这种实现会丢弃 move 语义吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24773636/