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

时间:2017-08-21 19:08:44

标签: 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::move中的std::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.

2 个答案:

答案 0 :(得分:22)

没有。请记住,std::move并没有移动任何东西,而是通过remove_reference_t获得了荣耀。因为在你的情况下它被转换为const rvalue引用(因为std::remove_reference_t<const T>const T),它不会绑定到rvalue引用重载push_back(T&& ),而是绑定到const lvalue引用一个 - push_back(const T& )

答案 1 :(得分: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);
    }
}