所以我昨天在youtube上看了c++视频,偶然发现了一个关于C++-11右值引用和移动语义的视频。我想我从广义上理解了这个概念,但今天当我和助教一起浏览我的代码时,他问我为什么不在下面的代码中引用(比如std::pair<HostName, IPAddress>& p)。在这种情况下我根本没有想过这一点,但当他问我的时候,我记得视频中说“在C++-11中,你通常应该使用按值传递。”
我的问题是:在下面的代码中,std::pair<HostName, IPAddress> p会不会像std::pair<HostName, IPAddress>& p一样更好?移动语义会被使用吗?会有什么不同吗?
IPAddress NameServer::lookup( const HostName& host ) const {
auto it = std::find_if( vec.begin(), vec.end(),
[host] ( std::pair<HostName, IPAddress> p ) {
return p.first == host;
} );
...
}发布于 2013-02-28 23:18:36
在这种情况下,您应该通过const引用传递。当您最终想要生成所传递的值的副本或移动时,通过值传递是有意义的;如果您既不想复制也不想移动,尤其是如果您想只观察,则应该传递(const)引用。
在这里,您的lambda谓词不需要生成它在输入中接收到的对的任何副本:因此,没有理由通过值传递(也没有理由通过vaue捕获)。
IPAddress NameServer::lookup( const HostName& host ) const {
auto it = std::find_if( vec.begin(), vec.end(),
[&host] ( std::pair<HostName, IPAddress> const& p ) {
// ^^^^^ ^^^^^^
return p.first == host;
} );
...
}相反,考虑这种情况(典型的C++03代码):
struct A
{
A(string const& s) : _s(s) { }
private:
string _s;
};在C++11中,由于您有移动语义,而不是通过常量引用传递s,您可以简单地通过值传递并将其移动到成员变量中:
struct A
{
A(string s) : _s(move(s)) { }
private:
string _s;
};这是有意义的,因为我们总是最终生成所传递的值的副本。
正如Benjamin Lindley在注释中正确指出的那样,如果这是您可以接受的,您可以编写上述构造函数的重载,这些构造函数通过引用接受它们的参数:
struct A
{
A(string const& s) : _s(s) { } // 1 copy
A(string&& s) : _s(move(s)) { } // 1 move
private:
string _s;
};上面的版本只允许对左值执行一次复制,对右值执行一次移动,而通过值传递的版本总是执行一次额外的移动。因此,如果移动对于您的参数类型来说是一个开销很大的操作(对于string不是这种情况,但对于其他类型可能是这种情况),这种解决方案可能更可取。
但是,如果您的函数有多个参数,这样做可能会很麻烦。为了减少工作量,您可以编写一个单一的函数模板,该模板接受通用引用并完美转发其参数。This Q&A on StackOverflow与该主题相关。
https://stackoverflow.com/questions/15139080
复制相似问题