Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ MinGW中的全局重载运算符新建/删除_C++_Qt_Mingw_New Operator_Delete Operator - Fatal编程技术网

C++ MinGW中的全局重载运算符新建/删除

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

我想在我的应用程序中重载new/delete操作符,以捕获所有内存泄漏。它在Linux上运行良好。但是我在Windows上遇到了一个问题。New/delete重载仅适用于.exe,而不适用于.dll文件的调用。此外,如果在我的代码中创建了某个对象,但正在从.dll文件中删除,则会导致应用程序崩溃。参考资料说

版本(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;
}
使用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