使用std :: move是否有任何性能优势?

时间:2016-10-22 14:25:22

标签: c++ c++11

请考虑以下代码:

#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,但是在处理更大的对象时可能会有一些性能优势吗?

3 个答案:

答案 0 :(得分:5)

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

考虑过度简化(和天真)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对象,它必须完全按照其名称所说的 copy 内容进行操作。现在这是你需要支付字符串副本时必须支付的价格,但是如果你只是想使用字符串的状态并且不关心它后面发生了什么,那么你也可以移动它。

移动它只需要将other对象保留在某种有效状态,这样我们就可以使用other中的所有内容,这正是我们想要的。现在,我们所要做的就是复制我们的data指针所指向的内容,而不是将我们的data指针重新分配给other,我们基本上是在窃取other的内容,我们也会很好,并将原始的data指针设置为nullptr

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

在那里,这就是我们所要做的。这显然比复制构造函数正在复制整个缓冲区更快。

Example

答案 1 :(得分:1)

移动“int甚至char*等”原始“类型与复制它们没什么不同。

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

答案 2 :(得分:0)

是的,但这取决于您的应用程序的详细信息 - 对象的大小以及操作的频率。

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

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

一般情况下,除非您需要优化,否则不要进行优化。