C++,const引用其实比move快?
C++, const reference is actually faster than move?
测试此代码后:
#include <iostream>
#include <chrono>
#include <vector>
#include <string>
void x(std::vector<std::string>&& v){ }
void y(const std::vector<std::string>& v) { }
int main() {
std::vector<std::string> v = {};
auto tp = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 1000000000; ++i)
x(std::move(v));
auto t2 = std::chrono::high_resolution_clock::now();
auto time = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - tp);
std::cout << "1- It took: " << time.count() << " seconds\n";
tp = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 1000000000; ++i)
y(v);
t2 = std::chrono::high_resolution_clock::now();
time = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - tp);
std::cout << "2- It took: " << time.count() << " seconds\n";
std::cin.get();
}
我知道使用 const-reference 实际上比使用移动语义快 15 秒,这是为什么呢?我认为移动语义更快,否则,他们为什么要添加它们?我对移动语义有什么误解?谢谢
你的代码没有意义。这是您的代码的一个更简单的版本,用 int
代替并进行了清理。这是代码的汇编版本,使用 -std=c++11 -02
:
编译
右值函数和左值函数的汇编之间没有区别。无论是什么原因都无关紧要,因为测试本身不使用移动语义。
原因可能是因为编译器将这两个函数优化到同一个程序集。你对这两个函数都没有做任何事情,所以在程序集中做任何不同的事情没有意义比简单的 ret
.
这是一个更好的例子,这次,交换向量中的前两项:
具有讽刺意味的是,您可以看到第二个函数实际上只是在执行过程中自动调用右值引用版本。
假设调用 B 的函数 A 比仅执行函数 B 慢,x()
的速度应该优于 y()
。
std::move()
本身有额外的费用。其他所有事情都是不变的,调用 std::move()
比不调用 std::move()
的成本更高。这就是为什么 "move semantics" 在您给我们的代码中较慢的原因。 实际上,代码速度较慢,因为您实际上并没有做任何事情——这两个函数在执行时都只是 return。您还可以看到一个版本似乎调用了 std::move()
而另一个版本没有。
编辑:以上内容似乎不正确。 std::move()
通常不是真正的函数调用;它主要是一个 static_cast<T&&>
,它依赖于一些模板内容。
在我给你的例子中,我实际上是在使用移动语义。大多数程序集都比较重要,但您可以看到 y()
调用 x()
作为其执行的一部分。因此 y()
应该比 x()
.
慢
tl;dr:你实际上并没有使用移动语义,因为你的函数根本不需要做任何事情。让函数使用 copying/moving,你会发现即使程序集也使用部分 "move semantics" 代码作为其复制代码的一部分。
测试此代码后:
#include <iostream>
#include <chrono>
#include <vector>
#include <string>
void x(std::vector<std::string>&& v){ }
void y(const std::vector<std::string>& v) { }
int main() {
std::vector<std::string> v = {};
auto tp = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 1000000000; ++i)
x(std::move(v));
auto t2 = std::chrono::high_resolution_clock::now();
auto time = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - tp);
std::cout << "1- It took: " << time.count() << " seconds\n";
tp = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 1000000000; ++i)
y(v);
t2 = std::chrono::high_resolution_clock::now();
time = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - tp);
std::cout << "2- It took: " << time.count() << " seconds\n";
std::cin.get();
}
我知道使用 const-reference 实际上比使用移动语义快 15 秒,这是为什么呢?我认为移动语义更快,否则,他们为什么要添加它们?我对移动语义有什么误解?谢谢
你的代码没有意义。这是您的代码的一个更简单的版本,用 int
代替并进行了清理。这是代码的汇编版本,使用 -std=c++11 -02
:
右值函数和左值函数的汇编之间没有区别。无论是什么原因都无关紧要,因为测试本身不使用移动语义。
原因可能是因为编译器将这两个函数优化到同一个程序集。你对这两个函数都没有做任何事情,所以在程序集中做任何不同的事情没有意义比简单的 ret
.
这是一个更好的例子,这次,交换向量中的前两项:
具有讽刺意味的是,您可以看到第二个函数实际上只是在执行过程中自动调用右值引用版本。
假设调用 B 的函数 A 比仅执行函数 B 慢,x()
的速度应该优于 y()
。
std::move()
本身有额外的费用。其他所有事情都是不变的,调用 std::move()
比不调用 std::move()
的成本更高。这就是为什么 "move semantics" 在您给我们的代码中较慢的原因。 实际上,代码速度较慢,因为您实际上并没有做任何事情——这两个函数在执行时都只是 return。您还可以看到一个版本似乎调用了 std::move()
而另一个版本没有。
编辑:以上内容似乎不正确。 std::move()
通常不是真正的函数调用;它主要是一个 static_cast<T&&>
,它依赖于一些模板内容。
在我给你的例子中,我实际上是在使用移动语义。大多数程序集都比较重要,但您可以看到 y()
调用 x()
作为其执行的一部分。因此 y()
应该比 x()
.
tl;dr:你实际上并没有使用移动语义,因为你的函数根本不需要做任何事情。让函数使用 copying/moving,你会发现即使程序集也使用部分 "move semantics" 代码作为其复制代码的一部分。