[英]Should a move constructor take a const or non-const rvalue reference?
在一些地方,我已经看到了复制和移动构造函数的推荐签名,如下所示:
struct T
{
T();
T(const T& other);
T(T&& other);
};
复制构造函数采用const引用,移动构造函数采用非const rvalue引用。
据我所知,这使我无法在从函数返回const对象时利用移动语义,例如下面的情况:
T generate_t()
{
const T t;
return t;
}
使用VC11 Beta对此进行测试,调用T
的复制构造函数,而不是移动构造函数。 甚至使用return std::move(t);
复制构造函数仍然被调用。
我可以看到这是有道理的,因为t
是const所以不应该绑定到T&&
。 在移动构造函数签名中使用const T&&
工作正常,并且有意义,但是你有问题,因为other
是const,如果需要将它们排除在外,你不能将其成员归零 - 它只会在所有成员是标量或具有正确签名的移动构造函数。
它看起来像,以确保移动构造函数在一般情况下已经作出的唯一途径t
摆在首位非const,但我不喜欢这样做- consting东西是好的形式,我不希望T
的客户知道他们不得不反对这种形式以提高性能。
所以,我想我的问题是双重的; 首先,移动构造函数应该采用const还是非const rvalue引用? 第二:我在这种推理中是对的吗? 我应该停止返回const的东西?
这应该是一个非const
右值引用。
如果将对象放在只读内存中,则无法从中窃取资源,即使其正式生命周期即将结束。 允许在C ++中以const
创建的对象存在于只读内存中(使用const_cast
尝试更改它们会导致未定义的行为)。
移动构造函数通常应该采用非const引用。
如果可以从const对象移动,通常意味着复制对象与从其“移动”对象一样有效。 此时,拥有移动构造函数通常没有任何好处。
你也是正确的,如果你有一个你可能想要移动的变量,那么它将需要是非const的。
据我所知,这就是Scott Meyers改变了他对C ++ 11函数中返回类类型对象的建议的原因。 通过const限定值返回对象确实可以防止无意中修改临时对象,但它也会禁止从返回值移动。
移动构造函数应该采用const还是非const rvalue引用?
它应该采用非const rvalue引用 。 rvalue引用首先在const表单中没有意义,因为你想要修改它们(在某种程度上,你想要“移动”它们,你想要自己的内部)。
此外,它们被设计为在没有 const的情况下使用,我相信const rvalue参考的唯一用途是Scott Meyers在本次演讲中提到的非常神秘的东西(从时间42:20到44:47)。
我在这种推理中是对的吗? 我应该停止返回const的东西?
我认为这是一个太普遍的问题。 在这种情况下,我认为值得一提的是, std::forward
功能将保留rvalue-ness和lvalue-ness以及const-ness,并且它还可以避免创建临时函数,因为正常函数会返回任何事情都传递给它。
这种返回也会导致右值引用被“损坏”到左值引用中,并且通常不需要它,因此,使用上述功能完美转发可以解决问题。
话虽这么说,我建议你只看一下我发布链接的话题。
除了在其他答案中所说的内容之外,有时还有移动构造函数或函数接受const T&&
。 例如,如果将按值返回const
对象的函数的结果传递给构造函数,则会调用T(const T&)
而不是T(T&&)
,如下所示(参见下面的函数g
)。
这是删除接受const
T&&
for std::ref
和std::cref
而不是接受T&&
重载的原因。
具体而言,重载解析期间的优先顺序如下:
struct s {};
void f ( s&); // #1
void f (const s&); // #2
void f ( s&&); // #3
void f (const s&&); // #4
const s g ();
s x;
const s cx;
f (s ()); // rvalue #3, #4, #2
f (g ()); // const rvalue #4, #2
f (x); // lvalue #1, #2
f (cx); // const lvalue #2
有关详细信息,请参阅此文章 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.