C++ valgrind可能在STL字符串上泄漏

TTb*_*boy 2 c++ string valgrind stl

我没有看到下面泄漏的原因.

#include <iostream>
#include <cstdlib>

int fail(const std::string str)
{
    std::cerr<< str << std::endl;
    exit(1);
}

const std::string usage()
{
    std::string a = "a";
    return a;
}   

int main()
{
    fail(usage());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Valgrind说:

==7238== 14 bytes in 1 blocks are possibly lost in loss record 1 of 1
==7238==    at 0x402377E: operator new(unsigned) (vg_replace_malloc.c:224)
==7238==    by 0x40E7C03: std::string::_Rep::_S_create(unsigned, unsigned, 
std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.10)
==7238==    by 0x40E8864: (within /usr/lib/libstdc++.so.6.0.10)
==7238==    by 0x40E89D5: std::string::string(char const*, std::allocator<char> const&) 
(in /usr/lib/libstdc++.so.6.0.10)
==7238==    by 0x80488EC: usage() (main.cpp:12)
==7238==    by 0x804897C: main (main.cpp:18)
==7238== LEAK SUMMARY:
==7238==    definitely lost: 0 bytes in 0 blocks.
==7238==      possibly lost: 14 bytes in 1 blocks.
==7238==    still reachable: 0 bytes in 0 blocks.
==7238==         suppressed: 0 bytes in 0 blocks.
Run Code Online (Sandbox Code Playgroud)

问题出在fail()函数中.当它退出()时,内存泄漏.

如果我注释退出(1); 然后没有可能的泄漏.

另外,如果我将签名从int fail(const std :: string str)更改为int fail(const char*str)

那么也没有可能的泄漏.我不喜欢这个解决方案,因为我使用的是fail(string +(LINE))类型的东西,但无论如何,这里发生了什么?

如果有人能解释,我会很高兴.

谢谢!

(upps.在我猜之前问过相同的问题,抱歉!Valgrind在为字符串赋值时报告内存泄漏)

Jam*_*lis 21

调用时exit(),不会调用自动对象(局部变量)的析构函数.

在您的特定示例中,std::string不会调用析构函数,因此std::string永远不会释放其拥有的内存.

如果你fail()拿a const char*,没有泄漏的原因是没有析构函数const char*; 当指针被销​​毁时,不会释放任何内容.如果指针指向动态分配的内存,那么在程序退出之前必须释放该内存(由您),否则会出现内存泄漏.如果它指向字符串文字,则没有内存泄漏,因为字符串文字具有静态存储持续时间(即,它们在程序的整个生命周期中都存在).

  • @Klaim:我看不出那个文件说我错了,但如果确实如此,那就错了.引用C++标准(第18.3/8节):"自动对象不会因调用`exit()`而被销毁." (10认同)
  • @Klaim:"常规清理"意味着破坏静态对象,调用使用`atexit()`注册的所有函数,并关闭任何流. (2认同)

Fru*_*nsi 8

James McNellis已经写了一个正确的答案.但是我想补充一些东西:

  1. 以不必调用exit()的方式编写软件总是一件好事 - 这有助于您改进整体设计,指定和理解对象的生命周期(除非是非常特殊的 - 相当低级别的情况......) .

  2. 如您所见,这在使用valgrind等工具时非常重要!"干净"的关机程序让您感觉安全,然后一切正常,正如您所期望的那样;)特殊情况下的清洁关机程序应该是每个软件的要求.

您应该考虑throw异常而不是调用某个fail()函数.抛出异常时,堆栈将被展开,因此std::string将调用您案例中的析构函数.