C++ shared_ptr最佳实践:字符串转大写示例代码问题与优化分析
关于C++智能指针使用的代码问题分析
这段小程序原本声称使用了智能指针,省去调用者手动free()返回缓冲区的麻烦,同时还能避免调用者忘记释放内存的问题,对应原始代码如下:
char* toupper(const string& s){ string ret(s.size(), char()); for(unsigned int i = 0; i < s.size(); ++i) ret[i] = (s[i] <= 'z' && s[i] >= 'a') ? s[i]-('a'-'A') : s[i]; return (char*) memcpy( chkedAlloc(1+ret.size(),*std::make_shared<char*>(nullptr)), ret.c_str(), 1+ret.size() ); }
其中chkedAlloc(n,A)会在捕获std::bad_alloc异常后返回new A[n]。
这段代码乍一看像是智能指针简化开发、提升安全性的教科书级用法,但实际上存在不少问题和可优化空间,以下是具体的改进点评:
- 最优方案是直接返回
string对象,其析构函数会在对象离开作用域时自动释放关联的存储空间,完全不需要手动管理堆内存。 - 原代码属于「
shared_ptr作为最后备选」的典型反例:shared_ptr的运行开销远高于unique_ptr,没有共享所有权需求时完全没必要使用shared_ptr。 - 这里需要纠正两个常见的错误认知:
- 不要误以为
shared_ptr是全场景线程安全的 - 不要误以为
unique_ptr无法转移给其他持有者
实际上持有者完全可以转移unique_ptr的所有权,只是同一时间仅能有一个持有者持有所有权,完全满足这个场景的需求。
- 不要误以为
- 转大写的逻辑可以考虑使用标准模板算法
std::transform实现,代码更简洁易维护。 - 如果示例代码是为了演示智能指针用法,可以优先选用
int作为示例类型而非std::string,能规避各类无关讨论。
优化后的参考实现如下:
unique_ptr<char*> toupper(const string& s){ string ret(s.size(), char()); for(unsigned int i = 0; i < s.size(); ++i) ret[i] = (s[i] <= 'z' && s[i] >= 'a') ? s[i]-('a'-'A') : s[i]; char *p = new char[1+ret.size()]; // 可自行补充try/catch(std::bad_alloc)逻辑 return make_unique<char*>((char*) memcpy(p, ret.c_str(), 1+ret.size())); } void f() { string s = "hello"; .. { char* p = *toupper(s); // 该作用域现在持有指针所有权 } // 离开作用域:堆上分配的内存由智能指针自动释放 .. }
内容的提问来源于stack exchange,提问作者Wasfi JAOUAD
相关产品推荐
相关产品推荐

