为什么 emplace_back("Hello") 调用 strlen?
Why does emplace_back("Hello") call strlen?
在另一个问题上做了一个我觉得很有趣但无法完全解释的观察。考虑以下代码:
std::vector<std::string> v;
v.push_back("Hello, world!"); // Doesn't call strlen.
v.emplace_back("Hello, world!"); // Calls strlen.
如果您查看程序集,emplace_back
generates a call to strlen
, whereas push_back
does not(使用 -Ofast
在 gcc 8.1 和 clang 6.0 中测试)。
为什么会这样?为什么 emplace_back
不能优化这里的 strlen
调用?我最初的想法是 push_back
在 函数调用之前隐式创建 std::string
(因此 std::string
构造函数直接传递了字符串文字,这得到最佳处理),而 emplace_back
在 函数调用后创建 std::string
(因此 std::string
构造函数被 forwarded 字符串文字,我认为它已经从 const char [N]
衰减到 const char *
,因此需要 strlen
调用)。
但是emplace_back
takes a T&&
parameter, and my tests show that the string literal shouldn't be decaying to a pointer here。显然我忽略了一些东西。
strlen
调用在慢路径的外联函数体中;该函数体必须对 const char (&)[42]
类型的所有参数有效(在您的 godbolt 示例中),包括并非源自 41 个字符的字符串文字且没有嵌入空值的参数。
快速路径被内联到 foo
中,它会在编译时计算长度。
std::vector<std::string> v;
v.push_back("Hello, world!"); // Doesn't call strlen.
v.emplace_back("Hello, world!"); // Calls strlen.
如果您查看程序集,emplace_back
generates a call to strlen
, whereas push_back
does not(使用 -Ofast
在 gcc 8.1 和 clang 6.0 中测试)。
为什么会这样?为什么 emplace_back
不能优化这里的 strlen
调用?我最初的想法是 push_back
在 函数调用之前隐式创建 std::string
(因此 std::string
构造函数直接传递了字符串文字,这得到最佳处理),而 emplace_back
在 函数调用后创建 std::string
(因此 std::string
构造函数被 forwarded 字符串文字,我认为它已经从 const char [N]
衰减到 const char *
,因此需要 strlen
调用)。
但是emplace_back
takes a T&&
parameter, and my tests show that the string literal shouldn't be decaying to a pointer here。显然我忽略了一些东西。
strlen
调用在慢路径的外联函数体中;该函数体必须对 const char (&)[42]
类型的所有参数有效(在您的 godbolt 示例中),包括并非源自 41 个字符的字符串文字且没有嵌入空值的参数。
快速路径被内联到 foo
中,它会在编译时计算长度。