4

在为我自己的内存管理器尝试一些内存跟踪和准备时,我尝试覆盖新的运算符。关于 Flipcode 的文章是我在此过程中的主要指导方针 ( http://www.flipcode.com/archives/How_To_Find_Memory_Leaks.shtml )。

在实现了该文章中描述的技术之后,我遇到的问题是,在 STL 中的某个地方,“crtdbg.h”被直接或间接地通过一些被包含的头文件包含(使用 Visual Studio 2010) .

这会导致错误:

[...]10.0\vc\include\crtdbg.h(1078): error C2365: 'operator new' : redefinition; previous definition was 'function'
[...]10.0\vc\include\crtdbg.h(1078): error C2078: too many initializers
[...]

通过放置“_CrtDumpMemoryLeaks()”而不包括头文件来进行快速检查,这证实了我怀疑头文件确实包含在 STL 文件中。

// The header files that should be included for using the CrtDumpMemoryLeaks:
//#define _CRTDBG_MAP_ALLOC
//#include <stdlib.h>
//#include <crtdbg.h>
//...
_CrtDumpMemoryLeaks()

撇开实现我自己的新/删除是一个好主意不谈,我想知道如何在仍然使用一些标准库功能并且没有这些重新定义错误的情况下拥有自己的新/删除实现。


代码如下所示:

内存调试.h

#ifndef _MEM_DEBUG_H
#define _MEM_DEBUG_H

#ifdef _DEBUG
    void * operator new( unsigned int size, const char *filename, int line );
    void operator delete( void *ptr );

    #define DEBUG_NEW new(__FILE__, __LINE__)
    #define new DEBUG_NEW
#endif

#endif

内存调试.c

#ifdef _DEBUG
void * operator new( unsigned int size, const char *filename, int line )
{
    void *ptr = (void *)malloc(size);
    //AddTrack((DWORD)ptr, size, filename, line);
    return(ptr);
};

void operator delete( void *ptr )
{
    //RemoveTrack( (DWORD)ptr );
    free( ptr );
}
#endif

主文件

#include "memdebug.h"
#include <iostream>

void main()
{
    Test *pTest = new Test();
    std::cout << "end" << std::endl;
}

我解决它的方法是移动#define new DEBUG_NEW下面的<iostream>; 问题已解决,因为它不会重写crtdbg.h; 但是,这确实使必须确保始终在包含该crtdbg.h文件的可能标头之后执行此操作变得很麻烦。

我相信这只能通过为新操作员使用自定义名称并改用该名称来解决。我对么?

4

4 回答 4

3

好吧,我现在解决它的方法是,无需使用自定义的“新”定义,我制作了一个通用头文件,假设每个文件中都包含“Engine.h”。这可以通过使用Project Settings / Configuration Properties / C/C++ / Advanced中的强制包含文件来强制执行。

此文件包含#define(从 memdebug.h 中删除)

引擎.h

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#include <windows.h>

#include "MemoryNappy.h"

#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW

这会强制系统在自定义新定义之前考虑crtdbg.h,并且不会在那里更改新的。它第二次被包含在某个地方,它只是使用之前已经加载的数据。(在<iostream>include 的 include 之后 include 的情况下"engine.h")。

请注意,在使用可能做同样伎俩的第三方库时,覆盖新的运营商仍然是有风险的业务。这会导致使用此处使用的模式重写这些文件的新运算符。在这种情况下,您可能需要重新考虑在此片段中使用自定义新定义:

#define myNew new(__FILE__, __LINE__)

(也在http://www.flipcode.com/archives/Detecting_Memory_Leaks.shtml中描述)

于 2011-02-20T13:17:33.927 回答
2

在我们的一个应用程序中,我们在应用程序级别重命名所有地方,new然后xnew将调试宏定义为仅作用于xnew.

new其用作宏并将其重新定义为自定义分配器也会出现问题。不幸的是,用于分配的 C++ 语法使调试包装器更难进行。

于 2011-02-19T22:23:33.547 回答
0

在 Visual Studio 2010 上,我能够做到这一点,而无需重新定义新的或自定义的新定义。我创建了一个包含以下内容的头文件:

#pragma once
//_CRTDBG_MAP_ALLOC
//_CRTDBG_MAP_ALLOC_NEW
#define _CRTDBG_MAP_ALLOC
#define _CRTDBG_MAP_ALLOC_NEW
#include <stdlib.h>
#include <crtdbg.h>

并在Project Settings / Configuration Properties / C/C++ / Advanced中使用已经讨论过的选项Forced Include File强制将其包含在每个源文件中。实际上,crtdbg.h 已经对new进行了自定义定义,同时对常规new进行了取消定义。为了确保一切顺利,我将 _CRTDBG_MAP_ALLOC 和 _CRTDBG_MAP_ALLOC_NEW 添加到预处理器定义列表中,位于:项目设置/配置属性/C/C++/预处理器中。

希望这将有助于解决这个问题。

于 2013-03-27T18:42:12.273 回答
-1

试试_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);——如我的博文中所述,无需new重新定义。

于 2011-11-09T05:05:24.850 回答