使用std::move是否有任何性能上的好处?

Does the use of std::move have any performance benefits?

本文关键字:性能 任何 std move 是否 使用      更新时间:2023-10-16

请考虑以下代码:

#include <iostream>
#include <vector>
#include <utility>
std::vector<int> vecTest;
int main() 
{
    int someRval = 3;
    vecTest.push_back(someRval);
    vecTest.push_back(std::move(someRval));
    return 0;
}

因此,据我所知,someRval的值将在第一次调用push_back()时复制到vecTest中,但在第二次调用someRval时产生x值。我的问题是,会有任何性能上的好处吗?我的意思是,可能不会对int有任何好处,但在处理更大的对象时可能会有一些性能上的好处吗?

移动的性能优势通常来自于动态分配被排除。

考虑一个过度简化(且幼稚)的string(缺少复制赋值操作符和移动赋值操作符):

class MyString
{
public:
    MyString() : data(nullptr) {}
    ~MyString()
    {
        delete[] data;
    }
    MyString(const MyString& other) //copy constructor
    { 
        data = new char[strlen(other.c_str()) + 1]; // another allocation
        strcpy(data, other.c_str()); // copy over the old string buffer
    }
    void set(const char* str)
    {
        char* newString = new char[strlen(str) + 1];
        strcpy(newString, str);
        delete[] data;
        data = newString;
    }
    const char* c_str() const
    {
        return data;
    }
private:
    char* data;
};

这一切都很好,但是如果字符串变长,这里的复制构造函数可能会很昂贵。然而,复制构造函数需要复制所有内容,因为它不允许触及other对象,它必须完全按照其名称所述,复制内容。现在,如果你需要字符串的副本,这就是你必须付出的代价,但是如果你只想使用字符串的状态,而不关心之后会发生什么,你不妨移动它。

移动它只需要让other对象处于一些有效状态,这样我们就可以使用other中的一切,这正是我们想要的。现在,我们所要做的不是复制data指针指向的内容只是将data指针重新赋值给other指针,我们基本上是在窃取other的内容,我们也会很好地将原来的data指针设置为nullptr:

MyString(MyString&& other)
{
    data = other.data;
    other.data = nullptr;
}

好了,这就是我们要做的。这显然比复制构造函数那样复制整个缓冲区要快得多。

移动像int甚至char*这样的"原始"类型与复制它们没有什么不同。

复杂类型,如std::string,可以使用您愿意牺牲源对象状态的信息,以使移动比复制更有效。

可以,但这取决于应用程序的细节——对象的大小和操作的频率。

将其转换为r值并移动它(通过使用std:move())可以避免复制。如果对象的大小足够大,这可以节省时间(例如,考虑一个具有1,000,000个双精度的数组-复制它通常意味着复制4 MB或更多内存)。
另一点是频率——如果你的代码经常执行相应的操作,它可以加起来相当可观。

请注意,源对象在过程中被销毁(使不可用),这对于您的逻辑来说可能是可接受的,也可能是不可接受的——您需要理解它并相应地编写代码。如果您之后仍然需要源对象,那么它显然无法工作。

一般来说,除非你需要优化,否则不要优化。