2009-07-14 6 views
5

Tôi đang cố gắng để có được bộ nhớ phát hiện rò rỉ làm việc với sự giúp đỡ của hai bài báo này: http://msdn.microsoft.com/en-us/library/e5ewb1h3%28VS.80%29.aspx http://support.microsoft.com/kb/q140858/Rò rỉ bộ nhớ Phát hiện và ghi đè mới?

Vì vậy, trong stdafx.h của tôi, tôi bây giờ có:

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

#define new new(_NORMAL_BLOCK,__FILE__,__LINE__) 

Vấn đề duy nhất là, tôi có một lớp ghi đè hàm mới:

class Dummy 
{  
    //overloaded new operator 
    void FAR* operator new(size_t cb); 
} 

Bây giờ khi tôi biên dịch mã này, tôi nhận được: lỗi C2 059: lỗi cú pháp: 'liên tục' lỗi C2091: chức năng trả về chức năng

Bất kỳ ý tưởng làm thế nào tôi có thể sửa lỗi này?

+0

Đó là vấn đề với macro: ( – GManNickG

+0

Nếu bạn không sử dụng cửa sổ, tôi xin đề nghị valgrind – LiraNuna

+0

Tôi muốn sử dụng DUMA nếu tôi đang sử dụng Windows. – EFraim

Trả lời

9

Bạn có thể sử dụng chỉ thị pragma để lưu và khôi phục macro mới khi undefing cho quá tải. Xem [MSDN] (http://msdn.microsoft.com/en-us/library/hsttss76(VS.71).aspx) cho cú pháp chính xác

Ví dụ

#pragma push_macro("new") 
#undef new 
void FAR* operator new(size_t cb); 
#pragma pop_macro("new") 

Bạn có thể đặt những trong tiêu đề, ví dụ như

begin_new_override.h:.

#ifdef new 
#define NEW_WAS_DEFINED 
#pragma push_macro("new") 
#undef new 
#endif 

end_new_override.h:

#ifdef NEW_WAS_DEFINED 
#undef NEW_WAS_DEFINED 
#pragma pop_macro("new") 
#endif 

Và sau đó

#include "begin_new_override.h" 
void FAR* operator new(size_t cb); 
#include "end_new_override.h" 
+0

Thật tuyệt, tôi không biết điều này là có thể :-) –

1

Hãy thử #undef new trước định nghĩa lớp và sau đó #define new new... lại sau.

4

Thay vì xác định mới là điều gì đó khác biệt, tại sao không phải là toán tử quá tải mới?

Thêm những định nghĩa chức năng ở đâu đó trong không gian tên toàn cầu:

// operator new overloads 
void* operator new(const size_t size, const char* file, int line) throw(); 
void* operator new(const size_t size, const size_t align, const char* file, int line) throw(); 
void* operator new[](const size_t size, const char* file, int line) throw(); 
void* operator new[](const size_t size, const size_t align, const char* file, int line) throw(); 

// can't easily overload operator delete 
void operator delete(void* ptr) throw(); 
void operator delete[](void* ptr) throw(); 

// matched to the operator new overload above in case of exceptions thrown during allocation 
void operator delete(void* ptr, const char* file, int line) throw(); 
void operator delete[](void* ptr, const char* file, int line) throw(); 
void operator delete(void* ptr, const size_t align, const char* file, int line) throw(); 
void operator delete[](void* ptr, const size_t align, const char* file, int line) throw(); 

// global new/delete 
void* operator new(size_t size) throw(); 
void* operator new(size_t size, const std::nothrow_t&) throw(); 
void* operator new(size_t size, size_t align) throw(); 
void* operator new(size_t size, size_t align, const std::nothrow_t&) throw(); 

void* operator new[](size_t size) throw(); 
void* operator new[](size_t size, const std::nothrow_t&) throw(); 

void operator delete(void* ptr, const std::nothrow_t&) throw(); 
void operator delete[](void* ptr, const std::nothrow_t&) throw(); 

Sau đó, bạn có thể định nghĩa của riêng bạn macro mới trong đó kêu gọi thông qua các phiên bản phi toàn cầu và thực hiện các phiên bản toàn cầu để khẳng định hoặc cảnh báo nếu họ gọi lại (để bắt bất cứ điều gì trượt qua).

#define MY_NEW(s) new(s, __FILE__, __LINE__) 

Quá tải cấp lớp của bạn sẽ hoạt động như mong đợi nếu bạn gọi 'mới' trực tiếp trên lớp học. Nếu bạn muốn gọi MY_NEW trên lớp, bạn có thể nhưng bạn sẽ phải xác định lại tình trạng quá tải trong lớp để phù hợp với lớp mới của bạn.

+1

'__LINE__' là một' int', không phải là 'char *'. – Cornstalks

+0

Giúp tôi hiểu rõ quá tải cụ thể cho các toán tử mới và xóa. – Vinzenz

4

Xác định lại new qua #define ở cấp tiền xử lý là một ý tưởng tồi trong kinh nghiệm của tôi - bạn không chỉ phá vỡ quá tải operator new, mà còn có thể là một vài thứ khác.

Có tất cả các macro FILE và LINE mở rộng ở khắp mọi nơi làm cho phần .rodata và .data của bạn sưng lên với chuỗi tệp và số dòng và tạo nhiều mã hơn cho mỗi cuộc gọi.

Tốt hơn nhiều (nếu có nhiều nỗ lực hơn) để tận dụng sự tồn tại của thông tin gỡ lỗi (ví dụ: .pdb tệp) và sử dụng thư viện StackWalk64 của DbgHelp để thu thập thông tin ngăn xếp.

Quá tải các kết hợp khác nhau của toán tử mới và toán tử (mảng, nothrow, v.v.), để chúng lưu trữ và giải phóng thông tin ngăn xếp khi bộ nhớ được cấp phát và giải phóng.

Bạn thậm chí có thể lưu trữ thông tin này trong cấu trúc như std :: map < void *, StackInfo >, chỉ cần cẩn thận để không ghi lại allocs do chèn bản đồ gây ra (khóa toàn cầu có thể đủ cho một đơn) ứng dụng luồng, đa luồng được để lại dưới dạng bài tập cho người đọc).

Vì bạn đang ghi toàn bộ ngăn xếp cho bất kỳ phân bổ cụ thể nào, bạn có thể thực hiện một số phân tích cây thuận tiện, phân bổ nhóm (rò rỉ hoặc cách khác) bằng "hàm và con cháu" ... nếu bạn biết toàn bộ ngăn xếp từ thời gian phân bổ của họ.

+0

Ngẫu nhiên, nếu ai đó đã biết về một thư viện/bộ công cụ để làm điều này (lưu trữ thông tin phân bổ với dấu vết ngăn xếp) dưới cửa sổ - chặn các giải pháp thương mại - Tôi rất muốn nghe về nó, và sẽ vui vẻ cập nhật câu trả lời . Không có lý do để phát minh lại bánh xe. Phiên bản này tôi đã sử dụng trên một nền tảng được nhúng ... – leander

+1

Thử nhìn vào các dấu vết ETW có cửa sổ. Các công cụ này miễn phí và nhỏ, do đó có thể được giảm xuống trên các máy khách để giúp gỡ lỗi. Ngoài ra, bạn có thể đăng thêm thông tin vào các dấu vết của mình từ ứng dụng của bạn. họ có thể theo dõi phân bổ bộ nhớ và deallocations và nắm bắt thông tin stack cho mỗi một. Điều khó khăn nhất là thiết lập WPA để hiển thị thông tin bạn muốn có thể gây khó khăn. Có một số video hữu ích được liên kết tại đây để giúp bạn bắt đầu: https://randomascii.wordpress.com/2014/08/19/etw-training-videos-available-now/ – 0xC0DEFACE