我的代码经常将C ++字符串转换为CStrings,我想知道原始字符串是否在堆栈上分配,CString是否也会在堆栈上分配?例如:
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
时,我知道指针在堆栈上。我问的是它指向的内容是在堆还是堆栈上。
答案 0 :(得分:36)
string s = "Hello world";
char* s2 = s.c_str();
s2会在堆栈上还是在堆中分配?换句话说......我需要删除s2吗?
不,不要 delete s2
!
s2
在堆栈中;如果代码位于全局或命名空间范围,则s2
将位于某个静态分配的动态初始化数据段中。无论哪种方式,它都是指向字符的指针(在这种情况下恰好是'H'
的文本内容的ASCIIZ表示中的第一个s
字符。该文本本身就是s
对象感觉构建该表示的任何地方。实现被允许这样做,但他们喜欢,但std::string
的关键实现选择是它是否提供“短字符串优化”,允许非常短的字符串直接嵌入s
对象和"Hello world"
是否足够短以从优化中受益:
s2
将指向s
内的内存,这将按照s2
上面的说明进行堆叠或静态分配s
内会有一个指向动态分配(自由存储/堆)内存的指针,其中会出现{Hello,\ _0}内容由.c_str()
返回的内容,并且s2
将是该指针值的副本。请注意,c_str()
为const
,因此要编译代码,您需要更改为const char* s2 = ...
。
您不得delete s2
。 s2
对象仍由s
点所拥有和管理的数据将因const
或{{1}的非s
方法调用而失效超出范围。
s
s2现在会在堆上,因为它的起源是在堆上吗?
此代码无法编译,因为string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();
不是指针而且字符串没有像s
这样的构造函数。您可以将其更改为:
string(std::string*)
...或...
string* s = new string("Hello, mr. heap...");
后者会造成内存泄漏而没有用处,所以让我们假设前者。然后:
string s = *new string("Hello, mr. heap...");
......需要成为......
char* s2 = s.c_str();
s2现在会在堆上,因为它的起源是在堆上吗?
是。在所有场景中,特别是如果char* s2 = s->c_str();
本身在堆上,则:
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>
。
答案 1 :(得分:15)
c_str()
返回指向string
对象中内部缓冲区的指针 - 您永远不会free()
/ delete
。
只有当它指向的string
在范围内时才有效。此外,如果您调用string
对象的非const方法,则不再保证其有效。
http://www.cplusplus.com/reference/string/string/c_str/
(根据以下评论编辑清晰度)
答案 2 :(得分:4)
std::string::c_str()
会返回const char*
,而非char *
。这是一个很好的迹象,表明你不需要释放它。内存由实例管理(例如,请参阅this link中的一些详细信息),因此它仅在字符串实例有效时才有效。
答案 3 :(得分:4)
首先,即使您的原始字符串未在堆栈中分配,您似乎也相信。至少不完全。如果将string s
声明为局部变量,则只有string
对象本身“在堆栈中分配”。该字符串对象的受控序列在其他地方分配。您不应该知道它的分配位置,但在大多数情况下,它是在堆上分配的。即第一个示例中"Hello world"
存储的实际字符串s
通常在堆上分配,无论您在何处声明s
。
其次,关于c_str()
。
在C ++(C ++ 98)的原始规范中,c_str
通常返回指向某处分配的独立缓冲区的指针。同样,你不应该知道它的分配位置,但一般情况下它应该在堆上分配。大多数std::string
的实现都确保它们的受控序列始终为零终止,因此它们的c_str
返回了一个指向受控序列的直接指针。
在新的C ++规范(C ++ 11)中,现在要求c_str
返回指向受控序列的直接指针。
换句话说,在一般情况下,即使对于本地c_str
对象,std::string
的结果也将指向堆分配的内存。你的第一个例子与你在这方面的第二个例子不同。但是,在任何情况下c_str()
指向的内存都不归您所有。你不应该解除它。你甚至不应该知道它的分配地点。
答案 4 :(得分:2)
s2
仍在范围内, s
就会有效。它是s
拥有的内存指针。参见例如this MSDN documentation:“字符串的生命周期有限,并且由类字符串拥有。”
如果要在函数内部使用std::string
作为字符串操作的工厂,然后返回c样式的字符串,则必须为返回值分配堆存储。使用malloc
或new
获取空间,然后复制s.c_str()
的内容。
答案 5 :(得分:1)
s2会在堆栈上还是在堆中分配?
可以在任何一个。例如,如果std::string
类执行小型字符串优化,则数据将在堆栈(如果其大小低于SSO阈值)时驻留在堆栈上,否则将驻留在堆上。 (这都是假设std::string
对象本身在堆栈上。)
我需要删除s2吗?
不,c_str
返回的字符数组对象归字符串对象所有。
s2现在会在堆上,因为它的起源是在堆上吗?
在这种情况下,无论如何数据都可能存在于堆中,即使在进行SSO时也是如此。但是很少有理由动态分配std::string
对象。
答案 6 :(得分:0)
这取决于。如果我没记错的话,CString会复制输入字符串,所以不,你不需要任何特殊的堆分配例程。