You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Valgrind检测到意外内存泄漏,求C++程序泄漏根源分析

构造函数抛异常时Valgrind检测到的内存泄漏根源解析

问题代码

#include <iostream>
#include <cstring>
#include <stdexcept>

class cmdline {
  char *stored_file = nullptr;

public:

  cmdline(const int argc, char const* const* argv) :
    stored_file(argc < 6 ? throw std::logic_error("Not enough parameters") : new char[std::strlen(argv[1]) + 1]) { }
  ~cmdline() { delete[] stored_file; }
};

int main(int argc, char *argv[])
{
  using namespace std;

  cmdline *p;

  try {
    p = new cmdline(argc, argv);
  }
  catch(const logic_error& err) {
    cout << err.what() << endl;
    exit(1);
  }

  return 0;
}

疑问点

在cmdline类的构造函数中,当满足argc < 6条件时会抛出std::logic_error异常,原本认为构造函数不会分配任何内存,但使用valgrind --leak-check=full运行程序后,检测到了内存泄漏。

Valgrind检测输出

==9845== 
==9845== HEAP SUMMARY:
==9845==     in use at exit: 190 bytes in 2 blocks
==9845==   total heap usage: 5 allocs, 3 frees, 73,926 bytes allocated
==9845== 
==9845== 46 bytes in 1 blocks are possibly lost in loss record 1 of 2
==9845==    at 0x4841F11: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9845==    by 0x4966049: allocate (new_allocator.h:137)
==9845==    by 0x4966049: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) [clone .isra.0] (cow_string.h:3537)
==9845==    by 0x4966116: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) [clone .part.0] [clone .isra.0] (cow_string.h:3096)
==9845==    by 0x49664F7: std::logic_error::logic_error(char const*) (cow-stdexcept.cc:87)
==9845==    by 0x1093B9: cmdline::cmdline(int, char const* const*, int) (test.cpp:11)
==9845==    by 0x109267: main (test.cpp:22)
==9845== 
==9845== 144 bytes in 1 blocks are possibly lost in loss record 2 of 2
==9845==    at 0x48417AB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9845==    by 0x493BB44: __cxa_allocate_exception (eh_alloc.cc:284)
==9845==    by 0x1093A4: cmdline::cmdline(int, char const* const*, int) (test.cpp:11)
==9845==    by 0x109267: main (test.cpp:22)
==9845== 
==9845== LEAK SUMMARY:
==9845==    definitely lost: 0 bytes in 0 blocks
==9845==    indirectly lost: 0 bytes in 0 blocks
==9845==      possibly lost: 190 bytes in 2 blocks
==9845==    still reachable: 0 bytes in 0 blocks
==9845==                       of which reachable via heuristic:
==9845==                         stdstring          : 46 bytes in 1 blocks
==9845==         suppressed: 0 bytes in 0 blocks
==9845== 
==9845== For lists of detected and suppressed errors, rerun with: -s
==9845== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

泄漏根源分析

这两处"possibly lost"的内存并非来自你代码中new char[]的分配,而是异常机制本身的内存开销:

  1. 46字节的块:是std::logic_error内部存储错误消息的std::string分配的内存。当创建std::logic_error对象时,构造函数会把传入的C字符串复制到内部的字符串成员中,这部分内存是在堆上分配的。
  2. 144字节的块:是C++运行时通过__cxa_allocate_exception为std::logic_error异常对象本身分配的内存,用于在栈展开过程中传递异常。

内存未被释放的直接原因是catch块中调用了exit(1):
exit()会直接终止程序,跳过C++异常处理的栈展开收尾步骤——异常对象的销毁逻辑本应在栈展开完成后执行,调用exit()会导致这部分逻辑被跳过,异常对象及其内部的字符串内存都无法被正确释放,因此Valgrind标记为"possibly lost"。

修复方案

将catch块中的exit(1)替换为return 1,这样程序会正常完成栈展开流程,异常对象会被正确销毁,对应的内存也会被释放:

catch(const logic_error& err) {
  cout << err.what() << endl;
  return 1;
}

内容的提问来源于stack exchange,提问作者francesco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 03:58:12