为什么移动比通过 const& 传递更昂贵?
Why are moves more expensive than passing by const&?
我将一些对象在其生命周期结束前传递给构造函数。
int main(){
//I wanted to avoid short string optimization in this example.
const std::string a(25,"a");
const std::string b(25,"b");
const std::string c(25,"c");
Foo f{a,b,c};
}
对于 Foo 的构造函数,我考虑了两个选项。
const&
(调用字符串的复制构造函数):
Foo(const std::string & a,
const std::string & b,
const std::string & c)
:a(a)
,b(b)
,c(c)
{}
std::move
(调用字符串的移动构造函数):
Foo(std::string a,
std::string b,
std::string c)
:a(std::move(a))
,b(std::move(b))
,c(std::move(c))
{}
在 gcc 7
上使用 -01
,我得到了以下结果:
+-------------+-----------------------+
| constructor | assembly instructions |
+-------------+-----------------------+
| const& | 192 |
| move | 264 |
+-------------+-----------------------+
为什么 const&
指令少了?
我认为移动比通过复制构造函数创建新字符串更便宜。
将变量作为构造函数参数传递的经验法则是什么
这些参数的生命周期何时结束?
您没有调用移动构造函数。您的参数字符串是常量。所以当你对它们使用 std::move
时,结果是 const std::string&&
。这不会调用移动构造函数,其签名采用 std::string&&
.
如果编译器没有为 main 调用构造函数的特殊版本,那么 main
仍在调用具有签名 Foo(std::string a, std::string b, std::string c);
的函数
除非它是内联的,或者 gcc 复制它实际上以不同的方式传递 args,否则函数 定义 中的代码不能改变它的调用方式。
假设构造函数定义在一个单独的文件中,并且在编译 main
时甚至不可见,只有原型。这类似于仅使用 -O1
.
编译得到的结果
我将一些对象在其生命周期结束前传递给构造函数。
int main(){
//I wanted to avoid short string optimization in this example.
const std::string a(25,"a");
const std::string b(25,"b");
const std::string c(25,"c");
Foo f{a,b,c};
}
对于 Foo 的构造函数,我考虑了两个选项。
const&
(调用字符串的复制构造函数):
Foo(const std::string & a,
const std::string & b,
const std::string & c)
:a(a)
,b(b)
,c(c)
{}
std::move
(调用字符串的移动构造函数):
Foo(std::string a,
std::string b,
std::string c)
:a(std::move(a))
,b(std::move(b))
,c(std::move(c))
{}
在 gcc 7
上使用 -01
,我得到了以下结果:
+-------------+-----------------------+
| constructor | assembly instructions |
+-------------+-----------------------+
| const& | 192 |
| move | 264 |
+-------------+-----------------------+
为什么 const&
指令少了?
我认为移动比通过复制构造函数创建新字符串更便宜。
将变量作为构造函数参数传递的经验法则是什么
这些参数的生命周期何时结束?
您没有调用移动构造函数。您的参数字符串是常量。所以当你对它们使用 std::move
时,结果是 const std::string&&
。这不会调用移动构造函数,其签名采用 std::string&&
.
如果编译器没有为 main 调用构造函数的特殊版本,那么 main
仍在调用具有签名 Foo(std::string a, std::string b, std::string c);
除非它是内联的,或者 gcc 复制它实际上以不同的方式传递 args,否则函数 定义 中的代码不能改变它的调用方式。
假设构造函数定义在一个单独的文件中,并且在编译 main
时甚至不可见,只有原型。这类似于仅使用 -O1
.