问题

考虑以下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();
}
 

通过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
 

如您所见,可能会丢失在堆上分配的26个字节.我知道std::string类有一个12字节的结构(至少在我的32位x86拱和GNU编译器4.2.4上),以及“Hello,World!”与一个null终止器有14个字节.如果我正确理解,12字节结构包含一个指向字符串的指针,分配的大小和引用计数(如果我在这里错误,有人正确).

现在我的问题:如何存储与堆栈/堆有关的C字符串?声明时std::string(或其他STL容器)是否存在堆栈对象?

附:我已经读过某个地方,valgrind可能会报告使用STL容器(和“almost-containers”,例如std::string)的一些C程序中内存泄漏的虚假正面.我不太担心这个泄漏,但它确实激发了我对STL容器和内存管理的好奇心.

  最佳答案

其他人是正确的,您正在泄漏,因为您正在调用退出.要清楚,泄漏不是堆栈上分配的字符串,它是由字符串在堆上分配的内存.例如:

 struct Foo { };

int main()
{
    Foo f;
    die();
}
 

不会导致valgrind报告泄漏。

泄漏很可能(而不是确定),因为您在heap上分配内存的内部指针.基本_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.
 

它们的关键是_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();
}
 

这将报告valgrind中的可能泄漏.如果您注释我移动m_data valgrind的行将报告’仍然可以访问’.如果您取消注释我将m_data设置为0的行,您将得到一个明确的泄漏.

valgrind documentation 有更多关于可能泄漏和内部指针的信息。

  相同标签的其他问题

c++stringmemory-leaks