【发布时间】:2018-12-15 22:01:36
【问题描述】:
背景。
我曾经写过 C++ 代码,现在我又开始了。我正在阅读一些涵盖 c++11(及更高版本)功能的书籍。堆栈溢出问题也有很多复杂的答案,但我只需要一个简单的答案。
在处理指针时,我曾经遵循著名的三规则,但现在我看到有新的移动语义,因此该规则已重命名为五法则。在线阅读我已经看到 C++ 已经发展,现在还有复制省略。我现在有很多新概念。看看这个:
struct Test {};
auto getNewTest() { return Test(); }
auto x = getNewTest();
在这种情况下(假设启用了复制省略),唯一发生的副本应该是当我将值分配给 x 时(只有 1 个副本)。之前会有 2 个副本:1 个作为返回值,1 个作为 x 的值。
到目前为止一切顺利,但使用移动语义我可以实现相同的效果(如果我是正确的)!假设 Test 已经正确分配了移动操作;我可以这样称呼:
auto getNewTest() { return Test(); }
auto x = std::move(getNewTest());
问题
我明白,当我必须摆脱旧变量时,移动是好的,我可以将其所有内容移动到新变量中,而不是将其复制到新变量中。
碰巧我有一个像return SomeClass(1,2,3) 这样的声明,我想避免复制太多。 std::move() 是否执行零拷贝?因为复制省略避免了 1 个副本(返回值)并且由于复制构造函数而只执行 1 个副本。
我的猜测是,使用 std::move() 我窃取了从函数创建的对象,因此我的副本为零。我对么?总的来说,这可能是平庸的,但我花了很多时间。
【问题讨论】:
-
您的第一个示例将在任何体面的编译器上执行零拷贝。
-
std::move实际上什么都不做,它只用于将值传递给采用右值引用的重载函数变体。请注意,在 C++17 中,这些规则已更改(并且可能会在 C++20 中再次更改),因此在您的第一个示例中不会发生复制或移动。 -
std::move(getNewTest());没有意义,结果已经是右值了。 -
我正在使用 Visual Studio,它应该有一个不错的编译器,所以我不会担心。
-
嗯,vc++ 编译器因忽视标准、按自己的方式做事和忽视性能问题而臭名昭著。最近情况发生了变化,但是 vc++ 不支持 C++11 模式。只能在某些混合C++14+模式或C++17模式下编译。