我有一个char* p
,它指向一个以\0
结尾的字符串。如何以异常安全的方式从中创建C ++ string
?
这是一个不安全的版本:
string foo()
{
char *p = get_string();
string str( p );
free( p );
return str;
}
一个明显的解决方案是尝试捕捉 - 任何更简单的方法?
答案 0 :(得分:25)
string
foo()
{
shared_ptr<char> p(get_string(), &free);
string str(p.get());
return str;
}
这使用shared_ptr
中的auto_ptr
特有的非常具体的功能,或其他任何功能,即指定自定义删除器的功能;在这种情况下,我使用free
作为删除者。
答案 1 :(得分:3)
我可以问你在你的例子中期待什么例外吗?
在许多平台上(Linux,AIX),如果你的内存不足,new或malloc将永远不会失败,你的应用程序将被os杀死。
答案 2 :(得分:1)
Yup - 基于堆栈的展开。 Modern C ++ Design有一般解决方案,但在这种情况下你可以使用
struct Cleanup {
void* toFree;
Cleanup(void* toFree) : toFree(toFree) {}
~Cleanup() { free(toFree); }
private:
Cleanup(Cleanup&);
void operator=(Cleanup&);
};
无论你的std :: string发生了什么,当你的Cleanup对象超出范围时,都会调用free(toFree)。
答案 3 :(得分:1)
好吧,p
如果get_string()
返回NULL,则不会指向以0结尾的字符串;这就是问题,因为std::string
构造函数接受指向0终止的C字符串的指针不能处理NULL,这是一个0终止的C字符串,就像两个数十个香蕉一样。
所以,如果get_string()
是你自己的函数,而不是库函数,那么也许你应该确保它不能返回NULL。例如,你可以让它返回所寻找的std::string
本身,因为它知道它自己的状态。否则,我会使用this answer中的Cleanup
作为帮助来保证p
不会泄漏(正如Martin York在评论中所建议的那样):
string foo()
{
const char* p = get_string();
const Cleanup cleanup(p);
const std::string str(p != NULL ? p : "");
return str;
}
答案 4 :(得分:0)
对于这些情况,我们通常使用ScopeGuard:
string foo()
{
char *p = get_string();
ScopeGuard sg = MakeGuard(&free, p);
string str( p );
return str;
}