移动常量对象而不编译警告

Gar*_*and 14 c++ c++11 c++17

我使用Visual Studio 2017版本15.3.1测试了以下代码.

v.push_back(std::move(str1))按预期工作.它将内容移动str1到矢量中.

str2是一个常量字符串.由于常量字符串在创建后无法修改,因此我希望该v.push_back(std::move(str2))语句会导致编译器警告.但令我惊讶的是,没有编译器警告.走进它后,我发现push_back(const T&)实际上已经调用了过载.该std::movestd::move(str2)似乎没有任何效果.

我的问题:是否应该在尝试移动常量对象时发出编译器警告?

// Compiled with Visual Studio 2017 version 15.3.1
std::vector<std::string> v;

std::string str1 = "string 1";
v.push_back(std::move(str1));
// Call push_back(T&&). The contents of str1 is moved into the vector.
// This is less expensive, but str1 is now valid but unspecified.

const std::string str2 = "string 2";
v.push_back(std::move(str2));
// Call push_back(const T&). A copy of str2 is added into the vector.
// str2 itself is unchanged.
Run Code Online (Sandbox Code Playgroud)

Ser*_*eyA 21

不,记住,std::move不动任何东西,它是一个美化的演员remove_reference_t.因为在你的情况下,它被铸造成const右值引用(如std::remove_reference_t<const T>const T),它不绑定到右值引用过载push_back(T&& ),而是结合为const左值引用一个- push_back(const T& ).

  • @SergeyA从性能角度来看,是否存在从const对象调用std :: move是正确的情况?我想到的类似案例是clang如何警告悲观的移动(即`return std :: move(foo);`)因为它们阻止了复制.在这两种情况下,我认为最终结果将是相同的,但所采取的路径可能不是最有效的.我认为"这段代码可能没有做它看起来像它正在做的事情"是编译器警告的*完美*用例. (6认同)
  • @ 0x5453,无论好坏,编译器都无法洞察开发人员的大脑.编写的代码中没有任何内容可以为编译器提供任何可疑内容的指示. (3认同)
  • 几乎任何T都可以自由地调用`move()` - 但是它实际上是*被移动,复制还是被擦除完全取决于你传递给它的任何东西.如果你天真地应用它,对复制构造函数的调用实际上是相当普遍的.从本质上讲,`move`始终被视为建议,而不是要求.请记住,移动是一个可能的副本优化,它不是传递const-reference的替代品. (2认同)

The*_*isp 5

有一种简单的方法可以防止静态移动来自const:只需删除它即可.

#include <type_traits>
#include <string>

//Copy this line into your global header
template<class T> void move (const T& arg) = delete; //ADL

int main()
{
    {
        std::string str;
        std::string str2 = move(str);
    }

    {
        //error
        //const std::string str;
        //std::string str2 = move(str);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 考虑到你的ADL注释,每次使用`move`都需要`使用std :: move;`才能保持一致.否则,你将不得不改变`move()`和`std :: move()`之间的调用,这取决于你正在移动什么,哪种方法失败了.当然标准类型可以很好地运行,但标准类型肯定不是您将要移动的唯一类型. (7认同)
  • 我也不喜欢改变标准函数语义的想法.有人可能会花费大量时间来理解为什么移动不会像标准规定的方式那样起作用. (5认同)