2017-01-31 35 views
1

给定一个计划:警告有关调用构造函数复制时的std :: move'ing

#include <iostream> 
#include <vector> 

using namespace std; 

struct Vec { 
    Vec() = default; 

    Vec(const Vec& vec) 
     : v_(vec.v_) 
    { 
     cout << "copy Vec" << endl; 
    } 

    Vec(Vec&& vec) 
     : v_(std::move(vec.v_)) 
    { 
     cout << "move Vec" << endl; 
    } 

    vector<double> v_{}; 
}; 

struct T1 { 
    Vec Value; 
}; 

struct T2 { 
    T2(const T1& t1) 
     : Value(std::move(t1.Value)) 
    { 

    } 

    Vec Value; 
}; 

struct T3 { 
    T3(T1&& t1) 
     : Value(std::move(t1.Value)) 
    { 

    } 

    Vec Value; 
}; 

int main() { 
    T1 t1; 

    T2 t2{ t1 }; 

    T3 t3{ std::move(t1) }; 

    return 0; 
} 

输出:

copy Vec 
move Vec 

在荷兰国际集团t1.ValueVec构造函数这两种情况下我std::move”。

是否有可能在Clang(或其他编译器)中启用某些警告,因此它警告说移动实际上会调用复制构造函数?

(铛已经可以警告性能问题时,例如,我通过std::move(result)从函数返回一个std::unique_ptr。)

+2

请注意'的std :: move'实际上并没有移动任何东西。它只是演员。 – NathanOliver

+0

性能问题,当你std ::移动一个'unique_ptr'从函数返回它?你在说什么?这实际上解决了一个或两个指针分配。 – David

+0

@David:是的,但带有命名返回值elision,编译器可以将它变成* nothing *。也就是说,如果他没有不必要地使用'std :: move'。这是一个完全有效的警告。 –

回答

1

是否有可能使在Clang的一些警告(或其他编译器),所以它警告我,移动实际上调用复制构造函数?

移动的过程并不是专门调用std::move。那只是演员。当您调用移动构造函数/赋值运算符时,会发生移动。如果没有调用std::move(例如编译器警告过你的情况),可能会发生移动,并且正如你看到的,即使你使用std::move也不会发生移动。

您不能从const参考移动,因为它是const。运动具有破坏性,因此需要修改对象的能力。 const不允许。

移动最终是一个优化的复制操作。因此,执行复制而不是移动通常是可以的,特别是如果该类型没有移动构造函数。

如果你愿意,你可以写你自己的std::movestatic_assert S版的Tconst

template< class T > 
constexpr typename std::remove_reference<T>::type&& my_move(T&& t) 
{ 
    static_assert(!std::is_const<T>::value, "Cannot move from a const reference"); 
    return static_cast<typename std::remove_reference<T>::type&&>(t); 
} 
+1

'!std :: is_const > :: value':'int const&'不是'const'。 – Yakk

+0

@Yakk:嗯......为什么不是'const int&'被认为是'const'?标准只是说“T是'const限定”。 –

+1

引用不能是const限定的。它们可以引用一个const限定类型,但它们本身不是const限定的。这是为什么'const int&'是编写'int const&'的一种误导性方式的原因之一。 'const'适用于'int'这里。 – Yakk