C++ 如何编写具有仅移动属性的函数?
我有一个类型是移动只,复制是禁止的。 我想在某些系统中传递它,但我不确定对于采用该类型参数的函数使用哪种签名。这种类型的对象必须移动到系统中,不应进行复制 例如:C++ 如何编写具有仅移动属性的函数?,c++,c++11,move,rvalue-reference,C++,C++11,Move,Rvalue Reference,我有一个类型是移动只,复制是禁止的。 我想在某些系统中传递它,但我不确定对于采用该类型参数的函数使用哪种签名。这种类型的对象必须移动到系统中,不应进行复制 例如: #include <vector> class Foo { public: Foo( std::string name ) : m_name( std::move( name ) ){} Foo( Foo&& other ) : m_name( std::move( other.m_name
#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) );
}
#包括
福班
{
公众:
Foo(std::string name):m_name(std::move(name)){}
Foo(Foo&&other):m_名称(std::move(other.m_名称)){}
Foo&operator=(Foo&other){m_name=std::move(other.m_name);}
常量std::string&name()常量{return m_name;}
// ...
私人:
Foo(const Foo&);//=delete;
Foo&运算符=(const Foo&);//=delete;
// ...
std::字符串m_名称;
};
分类栏
{
公众:
无效添加(Foo Foo)/(1)
//或者。。。
无效添加(Foo和&Foo)/(2)
{
m_foos.emplace_back(std::move(foo));//如果add是模板,我应该使用std::forward吗?
}
私人:
std::向量m_foos;
};
无效测试()
{
酒吧;
加上(Foo(“你好”);
福福(“世界”);
添加(标准::移动(foo));
}
(假设我正在移动对象,两个签名都在VS2012中编译)
1和2之间的哪个签名应该是首选
看起来这两种方法都有效,但我认为一定有不同之处…这要看情况而定
如果要将对象移动到函数中,请按值获取它。编译器将自己进行移动,您将清楚地向调用方记录函数移动传递的参数。如果使用第二个参数,函数可能会移动参数,也可能不会移动参数,即使调用者必须使用std::move(foo)
。这可能会让人非常困惑
如果不想将对象移动到函数中,请使用左值引用。如果函数未发生变异,则将其设为常量;如果函数发生变异,则将其设为非常量。视情况而定
如果要将对象移动到函数中,请按值获取它。编译器将自己进行移动,您将清楚地向调用方记录函数移动传递的参数。如果使用第二个参数,函数可能会移动参数,也可能不会移动参数,即使调用者必须使用std::move(foo)
。这可能会让人非常困惑
如果不想将对象移动到函数中,请使用左值引用。如果函数未发生变异,则将其设置为常量;如果函数发生变异,则将其设置为非常量。从xvalue移动时,签名#1将花费2个移动构造,而签名#2只需要从xvalue移动1个移动构造。因此#2对我来说更合适。但只要搬家建筑成本低廉,任何一个签名都能完成这项工作。您想要:
:-)Signature one无法编译,因为您无法复制
Foo
s。您应该使用(2)。@SethCarnegie是的,它会编译。@SethCarnegie如果他使用右值引用调用它会怎么样?就像在他的最后一行示例中一样。@SethCarnegie它在VS2012中工作,当你移动对象时。签名一不会编译,因为你不能复制Foo
s。您应该使用(2)。@SethCarnegie是的,它会编译。@SethCarnegie如果他使用右值引用调用它会怎么样?就像在他的最后一行示例中一样。@SethCarnegie它在VS2012中工作,当你移动对象时。我真的想移动对象。对象类型的语义确实需要它,因为复制是无意义的(如std::thread或类似类型)。我会补充一些精确性。@Klaim那么签名#1就是正确的选择。你能补充解释一下为什么在2)函数可能移动参数,也可能不移动参数吗?我对此有点困惑。@Klaimvoid f(foo&&){}
不会移动参数。然而,void f(foo){}
。我的意思是,第一个签名强制移动,但第二个签名给实现留出了余地。我真的想移动对象。对象类型的语义确实需要它,因为复制是无意义的(如std::thread或类似类型)。我会补充一些精确性。@Klaim那么签名#1就是正确的选择。你能补充解释一下为什么在2)函数可能移动参数,也可能不移动参数吗?我对此有点困惑。@Klaimvoid f(foo&&){}
不会移动参数。然而,void f(foo){}
。我的意思是,第一个签名强制移动,但第二个签名为实现提供了余地。