为何返回字符串字面量比返回静态std::string性能更优?
为什么返回字符串字面量的
std::string比返回拷贝的static std::string更快? 问题背景
函数return_string通过返回字符串字面量构造std::string,而return_static_string返回预分配static std::string的拷贝。性能测试显示return_string运行速度明显快于return_static_string,以下是原因解释:
测试代码
#include <numeric> static std::string return_string(int type) { switch(type) { case 0: return "apple"; case 1: return "orange"; case 2: return "banana"; } return {}; } static void default_return_string(benchmark::State& state) { std::vector<int> v(10000); std::iota(v.rbegin(), v.rend(), 0); for (auto _ : state) { for (const auto &n : v) { auto ignore = return_string(n % 3); benchmark::DoNotOptimize(ignore); } } } BENCHMARK(default_return_string); static std::string return_static_string(int type) { static const std::string ap = "apple"; static const std::string ora = "orange"; static const std::string ba = "banana"; switch(type) { case 0: return ap; case 1: return ora; case 2: return ba; } return {}; } static void static_return_string(benchmark::State& state) { std::vector<int> v(10000); std::iota(v.rbegin(), v.rend(), 0); for (auto _ : state) { for (const auto &n : v) { auto ignore = return_static_string(n % 3); benchmark::DoNotOptimize(ignore); } } } BENCHMARK(static_return_string);
核心原因
字符串字面量返回的优化:返回字符串字面量时,编译器会触发返回值优化(RVO),C++17及以后更是强制实施复制消除——直接在调用方栈上构造
std::string,无额外内存分配或拷贝。同时,测试中的字符串长度都在**小字符串优化(SSO)**范围内(通常15/22字节,依实现而定),完全不需要堆内存,构造销毁开销极低。static字符串拷贝的开销:
return_static_string每次返回的是static std::string的拷贝,即便static对象仅初始化一次,每次返回都要执行std::string的拷贝构造。虽然SSO下是栈上复制,但仍需复制字符串内容、管理对象内部状态,比直接构造SSO字符串多了一次拷贝操作的开销。
优化方案:返回引用
改为返回const std::string&后,return_static_ref_string性能会反超return_string——此时无需任何拷贝或构造,仅返回已初始化static对象的引用,开销几乎为0。
优化后代码:
static const std::string& return_static_ref_string(int type) { static const std::string ap = "apple"; static const std::string ora = "orange"; static const std::string ba = "banana"; switch(type) { case 0: return ap; case 1: return ora; case 2: return ba; } return {}; } static void static_return_ref_string(benchmark::State& state) { std::vector<int> v(10000); std::iota(v.rbegin(), v.rend(), 0); for (auto _ : state) { for (const auto &n : v) { const auto& ignore = return_static_ref_string(n % 3); benchmark::DoNotOptimize(ignore); } } } BENCHMARK(static_return_ref_string);
内容的提问来源于stack exchange,提问作者q0987
相关产品推荐
相关产品推荐

