我有一个函数f
返回char*
。功能文档说:
The user must delete returned string
我想从中构建一个std::string
。琐碎的事情是:
char* cstring = f();
std::string s(cstring);
delete cstring;
使用C ++功能可以做得更好吗?我想写点像
std::string(cstring)
避免泄漏。
答案 0 :(得分:8)
std::string
将复制空终止字符串参数并管理该副本。没有办法让它获得你传递给它的字符串的所有权。所以你所做的是正确的,我建议的唯一改进就是检查nullptr
,假设它是f()
的有效返回值。这是必要的,因为std::string
构造函数采用char const *
要求参数指向有效数组,而不是nullptr
。
char* cstring = f();
std::string s(cstring ? cstring : "");
delete[] cstring; // You most likely want delete[] and not delete
现在,如果您不需要所有std::string
的界面,或者如果避免副本很重要,那么您可以使用unique_ptr
来管理字符串。
std::unique_ptr<char[]> s{f()}; // will call delete[] automatically
您可以通过char *
访问托管s.get()
,当delete
超出范围时,字符串将为s
。
即使您使用第一个选项,我建议将f()
的返回值存储在unique_ptr
中,然后再将其传递给std::string
构造函数。这样,如果构造抛出,返回的字符串仍将被删除。
答案 1 :(得分:2)
std::string
没有标准方法来获取您传递的缓冲区的所有权。
也不负责清理这样的缓冲区。
理论上,一个实现,知道所有内部细节,可以为std::string
添加一种方式来接管分配器分配的缓冲区,但我不知道任何实施的
也没有任何保证这样做实际上是有利的,具体取决于实施细节。
答案 2 :(得分:1)
此代码永远不会是正确的:
std::string s(cstring);
delete cstring;
带有字符指针的std::string
构造函数需要一个以NUL结尾的字符串。所以它是多个字符。
delete cstring
是标量删除。
您是否尝试从字符标量创建字符串(在这种情况下,为什么是间接?)
std::string s(cstring[0]);
delete cstring;
或者您有多个字符,应相应删除
std::string s(cstring);
delete [] cstring;
检查其他答案,了解建议的方法,以确保delete[]
被使用,例如
std::string(std::unique_ptr<char[]>(f()).get())
答案 3 :(得分:0)
std::string steal_char_buffer( std::unique_ptr<char[]> buff ) {
std::string s = buff?buff.get():""; // handle null pointers
return s;
}
std::string steal_char_buffer( const char* str ) {
std::unique_ptr<char[]> buff(str); // manage lifetime
return steal_char_buffer(std::move(buff));
}
现在您可以输入
std::string s = steal_char_buffer(f());
,您从std::string
中获得f()
。
您可能想要使steal_char_buffer
的参数成为const char*&&
。它几乎没有意义,但可能会导致一些有用的错误。
如果您可以更改f
的界面,请直接返回std::string
或std::unique_ptr<char[]>
。
另一个好主意是将f
包装在另一个返回std::unique_ptr<char[]>
或std::string
的函数中:
std::unique_ptr<char[]> good_f() {
return std::unique_ptr<char[]>(f());
}
和/或
std::string good_f2() {
auto s = good_f();
return steal_char_buffer( std::move(s) );
}