C++ MinGW中的全局重载运算符新建/删除
我想在我的应用程序中重载new/delete操作符,以捕获所有内存泄漏。它在Linux上运行良好。但是我在Windows上遇到了一个问题。New/delete重载仅适用于.exe,而不适用于.dll文件的调用。此外,如果在我的代码中创建了某个对象,但正在从.dll文件中删除,则会导致应用程序崩溃。参考资料说 版本(1-8)可替换:用户提供的非成员功能 在程序的任何地方、任何源中定义相同的签名 文件,替换默认版本。它的声明不需要修改 可见 我编写了最小Qt模板应用程序来测试这一点。此处mainwindow.cpp:C++ MinGW中的全局重载运算符新建/删除,c++,qt,mingw,new-operator,delete-operator,C++,Qt,Mingw,New Operator,Delete Operator,我想在我的应用程序中重载new/delete操作符,以捕获所有内存泄漏。它在Linux上运行良好。但是我在Windows上遇到了一个问题。New/delete重载仅适用于.exe,而不适用于.dll文件的调用。此外,如果在我的代码中创建了某个对象,但正在从.dll文件中删除,则会导致应用程序崩溃。参考资料说 版本(1-8)可替换:用户提供的非成员功能 在程序的任何地方、任何源中定义相同的签名 文件,替换默认版本。它的声明不需要修改 可见 我编写了最小Qt模板应用程序来测试这一点。此处mainwi
#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;
}
使用Qt 4.8.7/GCC 4.8.2和Qt 5.5.1/GCC 4.9.2对其进行测试。那么,如何在MinGW中全局重载new/delete
顺便说一句,我写了极小值来重现这个问题。它输出我
$ ./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
Windows不是Linux,您需要相应地操作 简言之,通常安全的做法是确保每个EXE/DLL将管理自己的内存,即由EXE/DLL分配的内存只能由同一个EXE/DLL释放。这意味着当DLL提供
createObj
函数时,它还应该提供destroboj
函数。当然,如果可以确保所有EXE和DLL使用相同的运行时DLL(相同的版本,没有静态运行时),则不必这样做。即使这样,EXE和DLL也不会共享它们的运算符new
/delete
使用内存调试器时,应将其对象文件链接到每个EXE和DLL。每个EXE/DLL都将有自己的内存分配器,并自行检测。我在GCC Bugzilla上找到了答案 刘浩写道: 如果您知道动态链接库(DLL)是如何运行的,这并不奇怪 Windows的工作原理与Linux上的共享对象(SO)不同 Windows没有动态链接器,例如Linux上的
ld.so
。
DLL中的符号在构建时解析,与Linux相反,
其中SO中的符号在加载时解析。DLL加载程序可以
将符号解析为地址,但它没有链接器那么强大
毕竟。因此,可执行文件不能使用其强符号
重写DLL中已解析的弱DLL
如果用户未定义大小释放函数,则默认值为
使用libstdc++*.dll中的一个,它调用弱的、默认的,
同一DLL中的非大小释放函数,这是唯一
当DLL已生成且无法重写时的候选项
对于EXE/DLL问题,您需要确保使用的是共享DLL C运行时支持。如果您没有,那么您将有两个单独的堆(每个模块中一个),其中一个堆的
malloc
不能从另一个堆中free
。我建议避免在dll中释放内存。最好将释放内存的责任分配给分配内存的组件。jumper0x08,这是无法避免的。删除父对象时删除所有子对象这是Qt的完全正确行为。来自模板的最小Qt应用程序(.exe)创建对象层次结构并仅删除根对象。将删除Qt库(.dll)中的子项。Richard,这不是malloc/free问题。这是操作员新建/操作员删除问题。如果您没有共享CRT,那么您有两个堆,新建/删除将无法工作,这是相同的问题。
$ ./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