【发布时间】:2017-09-03 16:57:04
【问题描述】:
我想在我的应用程序中重载新/删除运算符以捕获所有内存泄漏。它在 Linux 上运行良好。但是我在 Windows 上遇到了问题。新/删除重载仅适用于 .exe,但不适用于来自 .dll 文件的调用。此外,如果在我的代码中创建了某个对象但从 .dll 文件中删除它会导致应用程序崩溃。 Cppreference here 说
版本 (1-8) 可替换:用户提供的非成员函数 在程序的任何地方、任何来源中定义的相同签名 文件,替换默认版本。它的声明不需要 可见。
我编写了最小的 Qt 模板应用程序来测试它。这里mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <cstdio>
#include <cstdlib>
// replacement of a minimal set of functions:
void *operator new(std::size_t sz)
{
void *ptr = std::malloc(sz);
std::printf("global op new called, size = %zu, pointer = 0x%p\n", sz, ptr);
return ptr;
}
void operator delete(void* ptr) noexcept
{
std::printf("global op delete called, pointer = 0x%p\n", ptr);
std::free(ptr);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
输出:
global op new called, size = 20, pointer = 0x00c4f608
global op new called, size = 24, pointer = 0x00c4f648
global op new called, size = 16, pointer = 0x00b35bf8
global op new called, size = 24, pointer = 0x00c4f6a8
global op new called, size = 24, pointer = 0x00c4f868
global op new called, size = 24, pointer = 0x00c4f988
global op delete called, pointer = 0x00c4f608
已使用 Qt 4.8.7/GCC 4.8.2 和 Qt 5.5.1/GCC 4.9.2 进行了测试。那么如何在 MinGW 中全局重载 new/delete 呢?
P。 S. 我写了最少的test case 来重现这个问题。它输出我
$ ./main.exe
global op new called, size = 4, pointer = 0x003e17b8
global op new called, size = 4, pointer = 0x003e3d68
library delete called, pointer = 0x003e17b8
global op delete called, pointer = 0x003e3d68
【问题讨论】:
-
对于 EXE/DLL 问题,您需要确保您使用的是共享 DLL C 运行时支持。如果不是,那么您将有 2 个单独的堆(每个模块中一个),并且其中一个的
malloc不能是另一个的free。 -
我建议避免在 dll 中释放内存。最好将释放内存的责任分配给分配它的组件。
-
jumper0x08,这是无法避免的。删除父级时删除所有子级,这是 Qt 完全正确的行为。模板中的最小 Qt 应用程序 (.exe) 创建对象层次结构并仅删除根对象。子项将在 Qt 库 (.dll) 中被删除。
-
Richard,这不是 malloc/free 的问题。这是运营商新/运营商删除问题。
-
如果你没有共享 CRT 那么你有两个堆并且 new/delete 将不起作用。
标签: c++ qt mingw new-operator delete-operator