这个移动构造函数的实现是否抛弃了移动语义?
Does this implementation of a move constructor throw away move semantics?
如果我有一个像这样的C
类:
class C {
std::string s;
public:
C(std::string& s) : s(s) {}
C(std::string&& s) : C(s) {}
};
我扔掉移动语义从string&&
构造函数调用string&
构造函数?
是的,你丢掉了你的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构造的。任何被"移动"到预定目标的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-construct,吸收了第一个实例。当我们开始销毁所有这些东西时,只有一个S
实例仍然有效;另一个通过移动而死亡。
长话短说,如果你的目标是移动,你就是在射击自己。我希望能帮到你,不过如果没用的话,我完全愿意扔掉它。
当人们提到"完美转发"时,这不是指的。这只是一个调用复制构造函数的移动构造函数(我认为这就是您的意思)。这是完美的转发:
class Foo{
public:
template<typename TBar> Foo(TBar&& bar): m_str(std::forward<TBar>(bar)){}
private:
std::string m_str;
};
这里发生的事情是,由于模板参数演绎和引用折叠规则,TBar&&就是所谓的"通用引用",这意味着它可以将其类型解析为TBar
、TBar&
或TBar&&
(也可以添加const
和volatile
)。std::forward
就像它的名字所说的那样,将TBar解析到的任何内容(保留其推断的类型)"转发"给字符串的构造函数。
相关文章:
- 将对象移动到std::shared_ptr
- 何时在引用或唯一指针上使用移动语义
- 如何从具有移动语义的类对象中生成共享指针
- 将shared_ptr移动到<StructA>shared_ptr<变体<结构A、结构 B>>
- C / C++ 移位/偏移/向左或向右移动位图?
- MSVC将仅移动结构参数解释为指针
- 自定义先决条件对移动分配运算符有效吗
- 返回值优化:显式移动还是隐式
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- 为什么复制而不是移动数据元素?
- 可以使用移动语义更改或改进此C++代码吗?
- 使lambda不可复制/不可移动
- c++在使用指针时移动语义
- 将QGraphicsItem的移动区域限制在多边形区域内
- SendInput()鼠标移动计算
- 按值 C++ 返回时进行双倍移动
- 移动二维数组中的字符
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- 安全到标准:移动会员?
- 这个移动构造函数的实现是否抛弃了移动语义?