std::move 对堆栈中的对象有帮助吗?

Does std::move helps with objects on stack?

今天刚看到一个学院在做这个优化:

即,更改为:

std::string somestring =  "somestring";
std::map<std::string, int> myglobalmap;

std::string myfunction( const std::string& mystring, int myint )
{
    myglobalmap.insert( std::pair<std::string, int>( mystring, myint ) );
}
myfunction(somestring, 10)

收件人:

std::string somestring =  "somestring";
std::map<std::string, int> myglobalmap;

std::string myfunction( std::string mystring, int myint )
{
    myglobalmap[ std::move(mystring) ] = myint;
}
myfunction(somestring, 10)

他声称通过复制传递值 mystring 而不是将其作为常量引用传递会更快,因为移动操作只会对堆栈上的对象执行。但我不明白为什么这会有帮助。我搜索了移动运算符,发现它不是 move anything,它只是让我对 return 的表达成为一个参考。

那么,如果这是真的,通过复制传递值不会比通过引用传递它并调用 std::move 慢,或者在这种情况下调用 std::move 对堆栈中的对象有帮助吗?如果我理解正确,std::move 应该只对堆上的对象有帮助。然后,用堆栈上的东西调用它应该没有帮助还是有用?

相关问题:

  1. What is std::move(), and when should it be used?
  2. Is it possible to std::move local stack variables?

首先,我想说这改变了 myfunction 的行为。如果键已经存在于映射中,第一个版本不会插入整数。第二个版本用新值替换整数。

就是说,如果传递的字符串不在地图中,因此它会制作一个副本,这可能会稍微更有效率。如果 myfunction 传递了一个临时值,编译器可以移动构造(甚至优化移出),然后将其移入映射中。虽然 std::move 不移动任何东西,但使用它会导致 map::operator[] 使用右值引用重载,这又可以调用 std::string.

上的移动构造函数

但是,如果密钥已经存在,则可能会导致创建不需要的额外副本。

and I found out it does not move anything, it just makes my expression to return a reference.

这是正确的。至关重要的是,该函数的结果是一个 xvalue。

Then, if this is true, passing the value by copy would not be slower than passing it by reference and calling std::move or does calling std::move

std::string 的情况下(假设包含的字符串不是非常小),复制和移动比通过引用和移动的间接寻址慢。


在您的第一个示例中,您通过引用间接访问并始终制作副本。

在第二个示例中,仅当函数参数为左值时才进行复制。当参数是右值时,第二个比第一个快(只要存储的字符串足够长,差异显着)。


两个版本都有未定义的行为,因为函数被声明为 return 非空,但没有 return 值。

我错过了问题中的一个重点,在 myglobalmap.insert( 和新的 myglobalmap[ 之前有一个锁。

也就是说,变化是这样的:

std::string somestring =  "somestring";
std::map<std::string, int> myglobalmap;
std::mutex g_pages_mutex;

std::string myfunction( const std::string& mystring, int myint )
{
    std::lock_guard<std::mutex> guard(g_pages_mutex);
    myglobalmap.insert( std::pair<std::string, int>( mystring, myint ) );
    return "";
}
myfunction(somestring, 10)

收件人:

std::string somestring =  "somestring";
std::map<std::string, int> myglobalmap;
std::mutex g_pages_mutex;

std::string myfunction( std::string mystring, int myint )
{
    std::lock_guard<std::mutex> guard(g_pages_mutex);
    myglobalmap[ std::move(mystring) ] = myint;
    return "";
}
myfunction(somestring, 10)

因此,作为 @eerorika 提供的答案的扩展,执行的优化是在获取锁之前调用复制构造函数。这意味着第二个版本应该更快,因为复制是在不持有锁的情况下执行的。