pr1*_*268 10 c++ string memory-leaks
考虑以下C++程序:
#include <cstdlib> // for exit(3)
#include <string>
#include <iostream>
using namespace std;
void die()
{
exit(0);
}
int main()
{
string s("Hello, World!");
cout << s << endl;
die();
}
Run Code Online (Sandbox Code Playgroud)
通过valgrind运行这个显示了这个(一些输出为了简洁而修剪):
==1643== HEAP SUMMARY:
==1643== in use at exit: 26 bytes in 1 blocks
==1643== total heap usage: 1 allocs, 0 frees, 26 bytes allocated
==1643==
==1643== LEAK SUMMARY:
==1643== definitely lost: 0 bytes in 0 blocks
==1643== indirectly lost: 0 bytes in 0 blocks
==1643== possibly lost: 26 bytes in 1 blocks
==1643== still reachable: 0 bytes in 0 blocks
==1643== suppressed: 0 bytes in 0 blocks
Run Code Online (Sandbox Code Playgroud)
如您所见,堆上分配的26个字节可能会丢失.我知道这个std::string
类有一个12字节的结构(至少在我的32位x86 arch和GNU编译器4.2.4上)和"Hello,World!" 使用null终止符有14个字节.如果我理解正确,12字节结构包含指向字符串的指针,分配的大小和引用计数(如果我在这里错了,有人会纠正我).
现在我的问题是:如何在堆栈/堆中存储C++字符串?声明时是否存在std::string
(或其他STL容器)的堆栈对象?
PS我在某处读过valgrind 可能会报告某些使用STL容器(以及"几乎容器"等std::string
)的C++程序中的内存泄漏误报.我并不太担心这种泄漏,但它确实激起了我对STL容器和内存管理的好奇心.
GMa*_*ckG 11
调用exit
"终止程序而不离开当前块,因此不会破坏任何具有自动存储持续时间的对象".
换句话说,泄漏与否,你应该不在乎.当你打电话时exit
,你说"关闭这个程序,我不再关心其中的任何内容." 所以停止关怀.:)
显然它会泄漏资源,因为你永远不会让字符串的析构函数运行,绝对不管它如何管理这些资源.
其他人是正确的,你正在泄漏,因为你正在呼叫退出.要清楚,泄漏不是堆栈上分配的字符串,而是字符串在堆上分配的内存.例如:
struct Foo { };
int main()
{
Foo f;
die();
}
Run Code Online (Sandbox Code Playgroud)
不会导致valgrind报告泄漏.
泄漏是可能的(而不是确定的),因为你有一个指向堆上分配的内存的内部指针.basic_string负责这一点.从我的机器上的标题:
* A string looks like this:
*
* @code
* [_Rep]
* _M_length
* [basic_string<char_type>] _M_capacity
* _M_dataplus _M_refcount
* _M_p ----------------> unnamed array of char_type
* @endcode
*
* Where the _M_p points to the first character in the string, and
* you cast it to a pointer-to-_Rep and subtract 1 to get a
* pointer to the header.
Run Code Online (Sandbox Code Playgroud)
它们的关键是_M_p不指向堆上分配的内存的开始,它指向字符串中的第一个字符.这是一个简单的例子:
struct Foo
{
Foo()
{
// Allocate 4 ints.
m_data = new int[4];
// Move the pointer.
++m_data;
// Null the pointer
//m_data = 0;
}
~Foo()
{
// Put the pointer back, then delete it.
--m_data;
delete [] m_data;
}
int* m_data;
};
int main()
{
Foo f;
die();
}
Run Code Online (Sandbox Code Playgroud)
这将报告valgrind可能发生的泄漏.如果你注释掉我移动的行m_data,valgrind将报告'仍然可以访问'.如果取消注释我将m_data设置为0的行,您将获得明确的泄漏.
valgrind 文档提供了有关可能泄漏和内部指针的更多信息.