struct TestConstRef {
std::string str;
Test(const std::string& mStr) : str{mStr} { }
};
struct TestMove {
std::string str;
Test(std::string mStr) : str{std::move(mStr)} { }
};
在观看GoingNative 2013后,我了解到 sink 参数应始终按值传递并随std::move
一起移动。 TestMove::ctor
是应用这个成语的正确方法吗?是否有TestConstRef::ctor
更好/更有效的情况?
琐碎的制定者怎么样?我应该使用以下习语还是传递const std::string&
?
struct TestSetter {
std::string str;
void setStr(std::string mStr) { str = std::move(str); }
};
答案 0 :(得分:21)
简单的答案是:是的。
原因很简单,如果按值存储,您可能需要移动(从临时)或复制(从l值)。让我们用两种方式检查两种情况下会发生什么。
来自临时
一个限制:没有高效移动构造函数的类(例如std::array<T, N>
)因为那时你做了两个副本而不是一个副本。
来自l值(或const临时,但谁会这样做......)
一个限制:相同的...移动类似于复制的类。
所以,简单的答案是,在大多数情况下,通过使用接收器,您可以避免不必要的副本(通过移动替换它们)。
单一限制是移动构造函数与复制构造函数一样昂贵(或接近昂贵)的类;在这种情况下,有两个移动而不是一个副本是“最差的”。值得庆幸的是,这类很少见(数组是一种情况)。
答案 1 :(得分:11)
有点晚了,因为这个问题已经有了一个公认的答案,但无论如何......这是一个替代方案:
struct Test {
std::string str;
Test(std::string&& mStr) : str{std::move(mStr)} { } // 1
Test(const std::string& mStr) : str{mStr} { } // 2
};
为什么会更好?考虑两种情况:
来自临时(案例// 1
)
str
只调用一个move-constructor。
来自l值(案例// 2
)
只为str
调用一个复制构造函数。
它可能不会比这更好。
但等等,还有更多:
来电者方面没有生成其他代码!复制或移动构造函数(可能内联或不内联)的调用现在可以存在于被调用函数的实现中(此处:Test::Test
),因此只需要该代码的单个副本。如果使用by-value参数传递,则调用者负责生成传递给函数的对象。这可能会在大型项目中加起来,如果可能的话,我会尽量避免使用它。