使用 std::move 是否有任何性能优势?
Does the use of std::move have any performance benefits?
请考虑此代码:
#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
但在处理更大的对象时可能会有一些性能优势吗?
移动 "primitive" 类型,例如 int
甚至 char*
与复制它们没有什么不同。
复杂类型,如 std::string
,可以使用您愿意牺牲源对象状态的信息,使移动比复制更有效。
是的,但这取决于您的应用程序的细节 - 对象的大小和操作的频率。
将其转换为 r 值并移动它(通过使用 std:move()
)可避免复制。如果对象的大小足够大,这可以节省时间(例如,考虑一个包含 1 000 000 个双精度数的数组 - 复制它通常意味着复制 4 MB 或更多的内存)。
另一点是频率 - 如果您的代码经常执行相应的操作,则加起来会相当可观。
请注意,源对象在此过程中被销毁(变得不可用),这可能会或可能不会被您的逻辑接受 - 您需要理解它并相应地编写代码.如果之后您仍然需要源对象,那么它显然是行不通的。
一般情况下,除非需要优化,否则不要优化。
移动带来的性能优势通常来自排除了动态分配。
考虑一个过度简化(和天真的)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 内容。如果您需要字符串的副本,这是您必须付出的代价,但是如果您只想使用字符串的状态而不关心之后会发生什么,您也可以 move它。
移动它只需要让 other
对象处于 一些 有效状态,这样我们就可以使用 other
中的所有内容,这正是我们想要的。现在,我们所要做的不是复制我们的 data
指针指向的内容,而是将我们的 data
指针重新分配给 other
中的一个,我们基本上是在窃取other
的内容,我们也很好,将原始 data
指针设置为 nullptr
:
MyString(MyString&& other)
{
data = other.data;
other.data = nullptr;
}
好了,这就是我们要做的。这显然比像复制构造函数那样复制整个缓冲区要快得多。
请考虑此代码:
#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
但在处理更大的对象时可能会有一些性能优势吗?
移动 "primitive" 类型,例如 int
甚至 char*
与复制它们没有什么不同。
复杂类型,如 std::string
,可以使用您愿意牺牲源对象状态的信息,使移动比复制更有效。
是的,但这取决于您的应用程序的细节 - 对象的大小和操作的频率。
将其转换为 r 值并移动它(通过使用 std:move()
)可避免复制。如果对象的大小足够大,这可以节省时间(例如,考虑一个包含 1 000 000 个双精度数的数组 - 复制它通常意味着复制 4 MB 或更多的内存)。
另一点是频率 - 如果您的代码经常执行相应的操作,则加起来会相当可观。
请注意,源对象在此过程中被销毁(变得不可用),这可能会或可能不会被您的逻辑接受 - 您需要理解它并相应地编写代码.如果之后您仍然需要源对象,那么它显然是行不通的。
一般情况下,除非需要优化,否则不要优化。
移动带来的性能优势通常来自排除了动态分配。
考虑一个过度简化(和天真的)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 内容。如果您需要字符串的副本,这是您必须付出的代价,但是如果您只想使用字符串的状态而不关心之后会发生什么,您也可以 move它。
移动它只需要让 other
对象处于 一些 有效状态,这样我们就可以使用 other
中的所有内容,这正是我们想要的。现在,我们所要做的不是复制我们的 data
指针指向的内容,而是将我们的 data
指针重新分配给 other
中的一个,我们基本上是在窃取other
的内容,我们也很好,将原始 data
指针设置为 nullptr
:
MyString(MyString&& other)
{
data = other.data;
other.data = nullptr;
}
好了,这就是我们要做的。这显然比像复制构造函数那样复制整个缓冲区要快得多。