我有一个只移动的类型,禁止复制。 我想在一些系统中传递它,但我不确定哪种签名用于参数中采用该类型的函数。必须将此类对象移入系统,不应进行任何复制。
示例:
#include <vector>
class Foo
{
public:
Foo( std::string name ) : m_name( std::move( name ) ){}
Foo( Foo&& other ) : m_name( std::move( other.m_name ) ){}
Foo& operator=( Foo&& other ){ m_name = std::move( other.m_name ); }
const std::string& name() const { return m_name; }
// ...
private:
Foo( const Foo& ) ;//= delete;
Foo& operator=( const Foo& ) ;//= delete;
// ...
std::string m_name;
};
class Bar
{
public:
void add( Foo foo ) // (1)
// or...
void add( Foo&& foo ) // (2)
{
m_foos.emplace_back( std::move(foo) ); // if add was template I should use std::forward?
}
private:
std::vector<Foo> m_foos;
};
void test()
{
Bar bar;
bar.add( Foo("hello") );
Foo foo("world");
bar.add( std::move(foo) );
}
(两个签名都在VS2012中编译,假设我正在移动对象)
首选1和2之间的哪个签名?
看起来两者都有效,但我认为必须存在差异......
答案 0 :(得分:4)
签名#1从xvalue移动时将花费2个移动构造,而签名#2将从xvalues仅花费1个移动构造。因此#2对我来说听起来更好。但只要搬家建设便宜,任何一个签名都可以完成工作。你想要吗:
: - )
答案 1 :(得分:3)
取决于。
如果要将对象移动到函数中,请按值取值。编译器将自己进行移动,并且您将清楚地向调用者记录该函数移动传递的参数。如果您使用第二个,则函数可能会或可能不会移动参数,即使调用者必须使用std::move(foo)
。这可能非常令人困惑。
如果您不想将对象移动到函数中,请使用左值引用。如果函数没有变异,则使其成为常量,如果变异则变为非常量。