是否需要string.c_str()解除分配
Is string.c_str() deallocation necessary?
我的代码经常将C++字符串转换为C字符串,我想知道原始字符串是否在堆栈上分配。C字符串也会在堆栈上分配吗?例如:
string s = "Hello, World!";
char* s2 = s.c_str();
s2
是在堆栈上分配,还是在堆中分配?换句话说,我是否需要删除s2
?
相反,如果我有这个代码:
string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();
s2
现在会在堆上吗,就像它的原点在堆上一样?
为了澄清,当我问s2
是否在堆上时,我知道指针在堆栈上。我在问它指向的是在堆上还是在堆栈上。
string s = "Hello world";
char* s2 = s.c_str();
s2是在堆栈上分配,还是在堆中分配?换句话说。。。我需要删除s2吗?
不,不要delete s2
!
如果上述代码在函数内部,则s2
在堆栈上;如果代码在全局或命名空间范围内,则s2
将处于某个静态分配的动态初始化数据段中。无论哪种方式,它都是指向某个字符的指针(在本例中,该字符恰好是s
的文本内容的以null结尾的字符串表示中的第一个'H'
字符)。文本本身就在s
对象想要构建该表示的任何地方。实现可以随心所欲地这样做,但std::string
的关键实现选择是它是否提供";短串优化";允许非常短的字符串直接嵌入到s
对象中,以及"Hello world"
是否足够短以从该优化中受益:
- 如果是这样,则
s2
将指向s
内部的内存,该内存将像上面针对s2
所解释的那样进行堆栈或静态分配 - 否则,在
s
内部将有一个指向动态分配(自由存储/堆)存储器的指针;你好世界\0"地址由.c_str()
返回的内容将出现,并且s2
将是该指针值的副本
请注意,c_str()
是const
,因此要编译代码,需要更改为const char* s2 = ...
。
您不能delete s2
。s2
指向的数据仍然由s
对象拥有和管理,对s
的非const
方法的任何调用或超出范围的s
都将使其无效。
string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();
s2现在会在堆上吗,就像它的原点在堆上一样?
这段代码不编译,因为s
不是指针,字符串也没有像string(std::string*)
那样的构造函数。您可以将其更改为:
string* s = new string("Hello, mr. heap...");
或
string s = *new string("Hello, mr. heap...");
后者造成内存泄漏,没有任何用处,所以让我们假设前者。然后:
char* s2 = s.c_str();
需要成为。。。
const char* s2 = s->c_str();
s2现在会在堆上吗,就像它的原点在堆上一样?
是的。在所有场景中,特别是如果s
本身在堆上,则:
- 即使
s
中有一个短字符串优化缓冲区,c_str()
会向该缓冲区生成指针,它也必须在堆上,否则 - 如果
s
使用指向其他内存的指针来存储文本,那么该内存也将从堆中分配
但是,即使确信s2
指向堆分配的内存,您的代码也不需要解除分配该内存——当s
被删除时,这将自动完成:
string* s = new string("Hello, mr. heap...");
const char* s2 = s->c_str();
// <...use s2 for something...>
delete s; // "destruct" s and deallocate the heap used for it...
当然,通常只使用string s("xyz");
更好,除非您需要超出本地范围的生存期,否则需要std::unique_ptr<std::string>
或std::shared_ptr<std::string>
。
c_str()
返回指向string
对象中内部缓冲区的指针。你从来没有free()
/delete
它。
只有当它指向的string
在范围内时,它才有效。此外,如果您调用string
对象的一个非常量方法,它将不再保证有效。
请参阅std::string::c_str
首先,即使是原始字符串也不会像您所相信的那样在堆栈上分配。至少不完全是这样。如果您的string s
被声明为局部变量,那么只有string
对象本身是"在堆栈上分配的"。该字符串对象的受控序列被分配到其他地方。您不应该知道它被分配到哪里,但在大多数情况下,它是在堆上分配的。也就是说,第一个例子中s
存储的实际字符串"Hello world"
通常是在堆上分配的,而不管您在哪里声明s
。
其次,关于c_str()
。
在C++(C++98)的原始规范中,c_str
通常返回一个指向某个地方分配的独立缓冲区的指针。同样,您不应该知道它被分配到哪里,但在一般情况下,它应该在堆上分配。std::string
的大多数实现都确保它们的受控序列总是零终止的,所以它们的c_str
返回了一个指向受控序列的直接指针。
在C++(C++11)的新规范中,现在要求c_str
返回一个指向受控序列的直接指针。
换句话说,在一般情况下,c_str
的结果将指向堆分配的内存,即使对于本地std::string
对象也是如此。在这方面,你的第一个例子与你的第二个例子没有什么不同。但是,在任何情况下,c_str()
所指向的内存都不归您所有。你不应该取消分配它。你甚至不应该知道它被分配到哪里。
std::string::c_str()
返回const char*
,而不是char *
。这很好地表明你不需要释放它。内存是由实例管理的(例如,请参阅此链接中的一些详细信息),因此只有当字符串实例有效时,它才有效。
只要s
仍在范围内,则s2
将有效。它是指向s
拥有的内存的指针。例如,请参阅MSDN文档:"该字符串的生存期有限,并且由类字符串所有"
如果要在函数内部使用std::string
作为字符串操作的工厂,然后返回C样式字符串,则必须为返回值分配堆存储。使用malloc
或new
获取空间,然后复制s.c_str()
的内容。
s2是在堆栈上分配,还是在堆中分配?
可能在其中之一。例如,如果std::string
类进行小字符串优化,则如果数据大小低于SSO阈值,则数据将驻留在堆栈上,否则将驻留在堆上。(这都是假设std::string
对象本身在堆栈上。)
我需要删除s2吗?
否,c_str
返回的字符数组对象为字符串对象所有。
s2现在会在堆上吗,就像它的原点在堆上一样?
在这种情况下,数据可能无论如何都会驻留在堆中,即使在执行SSO时也是如此。但是很少有理由动态地分配一个std::string
对象。
这取决于情况。如果我没记错的话,CString会复制输入字符串,所以不需要,您不需要任何特殊的堆分配例程。
- 指针会被解除分配吗?
- 基于浅树的数据结构的内存分配器,用于频繁分配和解除分配
- 解除分配矩形 2D 数组会根据尺寸产生错误
- 为什么在正确解除分配内存时出现内存泄漏?
- 堆栈变量超出范围时是否解除分配?
- 如何在不使用 "new" 关键字的情况下解除分配创建的对象的内存?
- 在 QStandardItemModel 中解除分配项目
- 解除分配此特定 2D 阵列的内存
- C++删除数组只会解除分配第一项
- 在 c++ 中使用向量解除分配
- 与解除分配堆数组相关的语法混淆
- 解除分配与 C++ 中的结构关联的所有内存
- 是否随作用域分配和解除分配堆栈帧
- 如果我使用 std::function 来捕获 lambda,我应该担心它被解除分配吗?
- 如果清除了 std::map 是否确保内存被解除分配
- 在另一个结构中的结构内解除分配指针
- 由 strcpy 设置的解除分配字符 * 时内存泄漏?
- 自定义内存分配和多个继承类的解除分配
- libpq错误消息解除分配
- 程序在解除分配字符数组时崩溃