C++标准库之string返回值研究
先说结论(不一定适用所有环境):
1) GCC默认开启了返回值优化(RVO),除非编译时指定“-fno-elide-constructors”;
2) 现代C++编译器一般都支持返回值优化;
3) string的拷贝构造和拷贝赋值是浅拷贝。
测试环境:
1) gcc (GCC) 4.8.5
2) g++ (GCC) 4.8.5
3) libstdc++.so.6.0.19
注:g++默认开启了返回值优化,
使用“-O0”不能关闭编译器的返回值优化,
而应使用“-fno-elide-constructors”关闭返回值优化。
测试代码:
#include <stdio.h> #include <string>
// 借助mystring来观察构造、析构和赋值行为 class mystring: public std::string { public: mystring(); ~mystring(); mystring(const mystring& oth); // 拷贝构造 mystring(const char* str); mystring& operator =(const mystring& oth); // 拷贝赋值 };
mystring::mystring() { fprintf(stdout, "mystring::ctor\n"); }
mystring::~mystring() { fprintf(stdout, "mystring::dtor\n"); }
mystring::mystring(const mystring& oth) { fprintf(stdout, "mystring::ctor(copy)\n"); this->assign(oth.c_str()); }
mystring::mystring(const char* str) { fprintf(stdout, "mystring::ctor(char*)\n"); this->assign(str); }
mystring& mystring::operator =(const mystring& oth) { fprintf(stdout, "mystring::operator =\n"); this->assign(oth.c_str()); }
mystring foo() { mystring str("12345678"); // 调用构造函数mystring(char*) return str; // 返回临时对象str }
int main() { { { mystring str1 = foo(); fprintf(stdout, "%s\n", str1.c_str()); } fprintf(stdout, "\n"); }
{ { const mystring& str2 = foo(); fprintf(stdout, "%s\n", str2.c_str()); } fprintf(stdout, "\n"); }
return 0; } |
普通编译和运行:
$ g++ -g -o x x.cpp $ ./x mystring::ctor(char*) 12345678 mystring::dtor
mystring::ctor(char*) 12345678 mystring::dtor |
总结:默认情况下,返回值使用对象或const引用效果完全一样。
禁止返回值优化编译和运行:
$ g++ -g -o x x.cpp -fno-elide-constructors $ ./x mystring::ctor(char*) mystring::ctor(copy) mystring::dtor mystring::ctor(copy) mystring::dtor 12345678 mystring::dtor
mystring::ctor(char*) mystring::ctor(copy) mystring::dtor 12345678 mystring::dtor |
总结:使用const引用比对象方式,少了一次拷贝构造函数调用。
因为string拷贝构造是基于引用计数的浅拷贝,所以赋值的性能很高,细节请参见《https://blog.csdn.net/Aquester/article/details/88555787》。