Переопределить новый оператор в C ++, пока crtdbg.h вызывает конфликты - PullRequest
4 голосов
/ 19 февраля 2011

При попытке отслеживания памяти и подготовки моего собственного менеджера памяти я попытался переопределить новый оператор. Моим основным ориентиром в этом процессе была статья о флипкоде (http://www.flipcode.com/archives/How_To_Find_Memory_Leaks.shtml).

После реализации методов, описанных в этой статье, я остаюсь с проблемой, что где-то в STL "crtdbg.h" включается прямо или косвенно через некоторые из заголовочных файлов, которые включены (Использование Visual Студия 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()

Если оставить в стороне, что это хорошая идея, или не реализовывать свои собственные новые / удалять, мне интересно, как я могу иметь свои собственные новые / удаляемые реализации, при этом все еще используя некоторые стандартные функции библиотеки и не имея этих ошибок переопределения.


Код выглядит так:

memdebug.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

memdebug.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

main.cpp

#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 ]

3 голосов
/ 20 февраля 2011

Хорошо, способ, которым я решил это сейчас, без необходимости использовать пользовательское «новое» определение, заключается в том, что я создал общий заголовочный файл, скажем, «Engine.h», который включен в каждый файл. Это может быть принудительно выполнено с помощью Принудительное включение файла в Параметры проекта / Свойства конфигурации / C / C ++ / Advanced .

Этот файл содержит #define (удален из memdebug.h)

engine.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 перед настраиваемым new-define и не будет менять там новое. Второй раз он включается где-то вниз по линии, он просто использует данные, которые уже были загружены ранее. (В случае включения <iostream> после включения "engine.h").

Обратите внимание, что переопределение нового оператора по-прежнему рискованно, если используются сторонние библиотеки, которые могут выполнить то же самое. Это приводит к тому, что оператор new для этих файлов будет переписан с использованием шаблона, использованного здесь. В этом случае вы можете пересмотреть использование нового пользовательского определения, как в следующем фрагменте:

#define myNew new(__FILE__, __LINE__)

(также описано в http://www.flipcode.com/archives/Detecting_Memory_Leaks.shtml)

2 голосов
/ 20 февраля 2011

В одном из наших приложений мы прибегали к переименованию везде на уровне приложения new с помощью xnew, а затем определяем макрос отладки как действующий только на xnew.

Использование new и переопределение его как макроса может иметь проблемы также с пользовательскими распределителями. К сожалению, синтаксис C ++ для размещения затруднил отладку оболочек.

0 голосов
/ 27 марта 2013

В 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>

и принудительно включил его в каждый исходный файл с уже обсуждаемым параметром Принудительное включение файла в Параметры проекта /Свойства конфигурации / C / C ++ / Advanced .На самом деле, crtdbg.h уже делает это пользовательское определение new вместе с неопределенным определением new .И чтобы убедиться, что все будет работать гладко, я добавил _CRTDBG_MAP_ALLOC и_CRTDBG_MAP_ALLOC_NEW в список определения препроцессора , доступный в: Настройки проекта / Свойства конфигурации / C / C ++ / Препроцессор .

Надеюсь, что это поможет в этом вопросе.

0 голосов
/ 09 ноября 2011

Попробуйте _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); - , как описано в моем блоге , не требуется new переопределение.

...