string s = "Hello world";
char* s2 = s.c_str();
s2会被分配到栈上还是堆上?换句话说...我需要删除s2吗?
不需要 delete s2
!
如果上述代码在函数内部,则s2
位于堆栈上;如果代码处于全局或命名空间作用域,则s2
将位于某些静态分配的动态初始化数据段中。无论哪种方式,它都是指向字符的指针(在这种情况下,该字符恰好是s
的文本内容的null-terminated string_表示中的第一个'H'
字符)。该文本本身位于s
对象构建该表示时决定的位置。实现可以以任何方式执行此操作,但对于std::string
的关键实现选择是是否提供“短字符串优化”,允许非常短的字符串直接嵌入s
对象中,并且"Hello world"
是否足够短以从该优化中受益:
- 如果是这样,那么
s2
将指向s
内存中的地址,这将根据上面对s2
的解释而被分配到堆栈或静态内存中。
- 否则,在
s
内部将会有一个指向动态分配(自由存储区/堆)内存的指针,其中包含由.c_str()
返回地址的“Hello world\0”内容,并且s2
将是该指针值的副本。
请注意,c_str()
是const
的,因此为了使您的代码编译通过,您需要更改为const char* s2 = ...
。
您绝不能delete s2
。 s2
指向的数据仍然由s
对象拥有和管理,将受到任何调用非const
方法的s
或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();
delete s;
当然,通常最好只使用
string s("xyz");
,除非你需要超出局部范围的生命周期,否则可以使用
std::unique_ptr<std::string>
或
std::shared_ptr<std::string>
。