我真的需要了解在以下情况下如何C++管理内存:
案例-1:
string s1 = "ABCD";
s1= "EFGH";
在字符串值"ABCD"的内存中会发生什么?它会自动解除分配吗?还是这里的内存泄漏?
案例2:
char* val = "ABCD";
val = "EFGH";
与案例 1类似,案例 2 与案例 1 有何不同?
案例3:
string s1 = "ABCD";
string s2 = s1;
是否为值为"ABCD"的 s2 分配了单独的内存?还是 s1 和 s2 指向此处的相同内存位置? 在这种情况下,如何管理内存?
请分享一个链接以深入研究这些?任何建议肯定会对我有所帮助。
-
现代
std::string
实现大致遵循这些规则(这里也解释得很好(:- 短字符串(<=26 个字符?(使用称为 SSO 的优化在堆栈上分配。 字符串
- 长度超过堆上分配的字符串。std::string 实现在内部管理此处的分配和解除分配。
-
const char* x = "ABCD"
在静态存储中的堆栈上分配,指向它的指针存储在堆栈上。这可以从此处的CE链接中看到,其中rsp:rsp-8
指向.LC0
。
鉴于上述观察结果:
- 情况 1:它在堆栈上分配 x,然后将新值"EFGH"复制到 s1,而不分配更多的堆栈空间。CE 链接
- 情况 2:它使
val
指向存储"ABCD"的静态存储,然后指向"EFGH"所在的位置。CE 链接
情况 - 3:这将(未启用优化(在堆栈(CE 链路(上分配 2 个 std::string,遵循情况 1。
如注释中所述,替代std::string
实现是可能的,例如 (1( 那些不实现 SSO 的实现 (2( 实现写入时复制。
案例 1
string s1 = "ABCD";
string
处理内存分配以为您存储"ABCD"
。当string
析构函数超出范围时,将自动调用s1
,这将释放string
分配的内存。
s1 = "EFGH";
string
复制赋值运算符将使用"EFGH"
覆盖内存存储"ABCD"
。
案例2
char* val = "ABCD";
val = "EFGH";
Fred Larson 在上面的评论中回答了这个问题,你只是重新分配了一个指向静态字符串的指针。堆栈将仅为指针(而不是数据(分配内存,当指针超出范围时val
将自动释放。
案例3
string s1 = "ABCD";
string s2 = s1;
s2
将分配内存并复制s1
。复制赋值运算符的写入时复制实现只会在s2
发生突变时分配和复制内存。但是,从 C++11 开始,似乎不再允许 COW 实现std::string
(C++11 中 COW std::string 实现的合法性(。
案例4
下面是一个方案示例,在该方案中,您确实需要担心释放分配的内存。
如果需要一个string
来超过创建它的范围,则可以使用它。(在实践中,通常应避免使用此方法。请参阅下面的案例 5。
string* s1 = new string("ABCD");
delete s1;
在此示例中,string
仍在内部管理内存以存储"ABCD"
,但string
指针是堆分配的,并且当s1
超出范围时不会调用string
析构函数。在这种情况下,您负责使用delete
来确保在不再需要内存时清理内存s1
。
案例5
shared_ptr<string> s1 = make_shared<string>("EFGH");
shared_ptr
通常是要走的路,而不是new
和delete
。共享指针可防止由于编程错误而导致的大量内存泄漏。shared_ptr
为您处理delete
,并使用引用计数使string
保持活动状态,直到最后一个引用被销毁。