std::string 会删除通过 new 分配的 char 缓冲区吗?
这里是否存在内存泄漏?:
#include <iostream>
#include <string>
class A{
std::string value;
public:
A(){
char *tmp = new char[3];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
value = std::string(tmp);
}
std::string const& getValue() const {
return value;
}
};
int main(){
A a;
std::cout << a.getValue() << '\n';
}
由于该值是从指向new
ed内存的指针构造的,因此std::string
正在获取它的所有权,它也会破坏?还是我有责任照顾那个临时物品?如果是这样,销毁它的唯一方法是将其作为私有变量,否则它将超出范围(因为指针是在构造函数中创建的自动存储)。
那么这里的缓冲区是如何管理的呢?
Is here a memory leak?:
#include <iostream>
#include <string>
class A{
std::string value;
public:
A(){
char *tmp = new char[3];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
value = std::string(tmp);
}
std::string const& getValue() const {
return value;
}
};
int main(){
A a;
std::cout << a.getValue() << '\n';
}
since the value is constructed from pointer to new
ed memory, and thus the std::string
is taking the ownership of it, will it also destroy? Or is it my responsibility to take care of that temporary object? And if so, the only way to destroying it is via having it as private variable, otherwise it goes out of scope (since the pointer is with auto storage created in constructor function).
So how is here the buffer managed?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(5)
答案是否定的。我的意思是想象一下,如果它做到了,并且您这样做了(忽略缺少的 0),
char *tmp = new char[3];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
std::string value1 = std::string(tmp);
std::string value2 = std::string(tmp);
如果第二个字符串创建失败,您会非常沮丧
而且 std::string(const char*s)
无法判断内存for s
位于堆、堆栈或静态上。它所能看到的只是一个指针。即使它想窃取记忆,它也无法知道它是否可行
因此 std::string 取得了它的所有权,它也会销毁吗?
如果您拥有资源的所有权,则意味着您最终将释放该资源(除非您将其转让给其他所有者,并且除非所有权是共享的)。如果您不释放资源(或适用上述例外情况),则要么您没有获得所有权,要么您有错误。
std::string
只会删除 std::string
创建的缓冲区。 std::string
不会取得您创建的缓冲区的所有权。您对“std::string 正在取得所有权”的假设是错误的。
永远不要尝试猜测某些函数/构造函数是否拥有所有权。始终依靠文档来找出答案。
或者我有责任照顾那个临时物品吗?
是的。您负责释放您创建的分配(直到您将所有权转移到智能指针之类的东西)。
您创建的动态分配会泄漏,因为您没有释放它。
如果是这样,销毁它的唯一方法是将其作为私有变量,否则它就会超出范围
您可以在创建 std::string
后简单地删除它,因此您的缓冲区是不再使用。
重要! 接受 char*
的 std::string
构造函数要求指向的字符串以 null 结尾。您的字符串不包含空终止符,因此调用违反了前提条件。您的程序的行为是未定义的。
而且,分配是完全没有必要的。您可以通过编写如下所示的构造函数来实现预期的行为并修复未定义的行为和内存泄漏:
A(): value("abc") {}
但是如果我从另一个分配它的函数获取 char 指针怎么办
主要是,尽量避免调用此类函数。
但如果您没有其他选择,那么您必须了解该函数正在将分配的所有权转移给您(我想不出该函数会记录它使用 std::malloc 的任何其他原因) >)。一旦不再需要它,您必须使用 std::free 释放它。理想情况下,您应该使用智能指针之类的东西来执行此操作。
我使用了 uuid_unparse ,它给出了从 malloc 生成的 char 指针(请参阅其文档)
根据
uuid_t some_uuid = example_uuid();
constexpr std::size_t uuid_size = 36;
std::string str(uuid_size, '\0');
uuid_unparse(some_uuid, str.data());
最有趣的评论:
@MarekR 重点是,我尝试复制我得到的错误。我用过
uuid_unparse
它给出了从 malloc 生成的 char 指针(请参阅其
文档),但在处理 uuid 的类中我有 std::string。和
由于 std::string 没有所有权,我必须更改
仅处理 char 指针的类的实现 -
米兰赫拉博斯
显然,您正在以错误的方式使用 uuid_unparse 与 c++ ,当问题出现时,您提出了问题不反映实际问题。
我会按以下方式使用这个API:
std::string uuid_to_string(uuid_t uu)
{
char buff[37];
uuid_unparse(uu, buff);
return buff; // implicit conversion to std::string is done here.
}
或更奇特的方式来做到这一点:
std::string uuid_to_string(uuid_t uu)
{
std::string buff(size_t{36}, '\0');
uuid_unparse(uu, buff.data()); // since C++17 data returns `char *`
return buff;
}
About your code:
char *tmp = new char[3];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
value = std::string(tmp);
这有3个问题:
- 您正在分配未释放的内存(字符串不接管它的所有权) - 所以内存泄漏
- 您的缓冲区不包含以零结尾,因此当它传递给 std::string 时,这会导致未定义的行为,因为无法确定字符串的
- 代码过于复杂。在了解其目的是什么之后,我能够提供简单的解决方案。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
这个假设是不正确的。
std::string
不获取任何指针的所有权,构造函数采用char*
将数据复制到内部存储中。所以,是的,您必须delete[]
您new[]
'ed的内容。另外,如果您将
char*
传递给std::string
,它必须以 null 结尾:This assumption is incorrect.
std::string
doesn't take ownership of any pointer, constructor takingchar*
copies the data into internal storage. So yes, you have todelete[]
what younew[]
'ed.Also, if you are passing
char*
tostd::string
, it must be null terminated: