使用字面常量时传递std::string是否该用引用?示例时间差异解析
std::string参数传递:字面常量与引用的性能疑问
测试代码
bool funcWithoutReference(const std::string Text) { return Text == "Hello!"; } bool funcWithReference(const std::string& Text) { return Text == "Hello!"; } int main() { // Example 1: Average execution time: 13.652 sec for (int i = 0; i < 10000000; i++) { std::string text = "Hello"; funcWithoutReference(text); } // Example 2: Average execution time: 7.283 sec for (int i = 0; i < 10000000; i++) { funcWithoutReference("Hello"); } // Example 3: Average execution time: 7.249 sec for (int i = 0; i < 10000000; i++) { std::string text = "Hello"; funcWithReference(text); } // Example 4: Average execution time: 7.292 sec for (int i = 0; i < 10000000; i++) { funcWithReference("Hello"); } return 0; }
问题解答
1. 示例1与示例2的执行时间差异原因
示例1中,每次循环先创建std::string text对象,再以传值方式传递给函数。传值参数会触发std::string的拷贝构造函数,需要为形参分配内存并复制原对象的所有数据——这一操作在1000万次循环累加后,带来了显著的性能开销,导致执行时间较长。
示例2中,直接传递字符串字面量"Hello"给传值函数时,C++会先构造临时std::string对象,但编译器会触发拷贝消除优化:跳过临时对象到形参的拷贝步骤,直接在函数形参的内存位置构造临时std::string。这就避免了额外的拷贝开销,仅保留临时对象的构造开销,因此执行时间大幅降低。
2. 示例2与示例3、4执行时间接近的原因
- 示例3中,将已创建的
std::string变量以const引用方式传递,仅会为形参创建引用绑定,不会触发任何拷贝操作,开销极小,主要耗时在循环本身和字符串比较。 - 示例4中,将字面量传递给const引用时,编译器会构造临时
std::string对象并将引用绑定到该临时对象上(临时对象的生命周期会被延长至引用的生命周期),核心开销是临时对象的构造,和示例2中的临时对象构造开销一致。 - 示例2经过拷贝消除优化后,仅保留临时对象的构造开销,和示例3、4的核心耗时环节对齐,因此三者执行时间几乎一致。
关于拷贝的补充说明
并非只有传递变量时才会发生拷贝:
- 传递具名对象(如示例1中的
text变量)给传值参数时,一定会触发拷贝构造,产生拷贝开销; - 传递临时对象(如字面量构造的
std::string)给传值参数时,编译器会通过拷贝消除优化避免拷贝,此时不会产生额外的拷贝开销。
内容的提问来源于stack exchange,提问作者vekewi9562
相关产品推荐
相关产品推荐

