標籤:

operator new的問題?

我想統計軟體中內存調用,於是#define new new(__FILE__, __LINE__),然後重載了new,void* operator new(std::size_t size, const char* file, int line);但是編譯的時候總是報錯 error C2061: 語法錯誤: 標識符「nothrow?,因為代碼里很多地方用到了new (std::nothrow) XXX。於是我分別是試了一下情況:

1 注釋掉上面的宏,編譯可以通過,但是程序不會走到我寫的opertor new里(用的編譯器是vs2012 debug模式,應該是程序走到了系統自帶的其他的opertor new里);

2. 刪掉std::nowthorw,程序編譯正確,而且執行正確。

所有我又2個問題。

1.源碼中調用std::nothrow的地方太多了,我不想都刪除,請問編譯錯誤該如何解決;

2.在不刪除std::nothrow的情況下,想重載new操作,同時參數里傳遞__FILE__, __LINE__,這個宏該怎麼寫,需要同時兼容 new XXX和new ( (std::nothrow)) 兩種情況。


這個目標有點麻煩,但是——還是有比較接近的辦法!

首先,#define一個關鍵字很可能是一個未定義行為。但我們先拋開UB,分析一下可能的解決方案。

先說說題主的思路為什麼不行。題主糾結的一點是,一般的new表達式後面可以接一個用括弧括起來的、類似題目中說的std::nothrow這樣的placement parameter列表,例如

Foo *foo = new (std::nothrow) Foo;

這樣的列表會作為new運算符的參數而存在。當然,也可以沒有這樣的列表,例如

Foo *ptr = new Foo;

如果原本沒有這個列表,那我們可以通過

#define new new (__FILE__, __LINE__)

來『新建』一個列表,並通過重載new運算符來插入自定義邏輯;如果有,那我們也可以通過

#define new(...) new (__FILE__, __LINE__, ## __VA_ARGS__)

並實現另一個(帶不定個模板參數的)運算符重載來解決。然而,new(...)並不能處理第一種情況,這兩個宏又不能同時存在(宏不能重載),而且似乎也沒有有效的預編譯器魔法來把它們統一處理。這從根本上滿足不了題主的需求。

那麼換個思路,我們這麼實現:(來源:nvwa)

#include &
#include &

class NewHelper {
public:
NewHelper(const char* file, int line) : file_(file), line_(line) {}

template &
T* operator -&>* (T* ptr) {
std::cout &<&< "Allocated a variable of size " &<&< sizeof(T) &<&< " at " &<&< file_ &<&< ":" &<&< line_ &<&< std::endl; return ptr; } private: const char* file_; const int line_; }; #define new NewHelper(__FILE__, __LINE__) -&>* new

int main() {
int *p = new int;
int *q = new (std::nothrow) int;
return 0;
}

簡單解釋一下這個實現:

如果允許先做真正的new,然後把new的結果轉發一遍,在『轉發一遍』的過程中插入一些自定義邏輯,豈不美哉?類似寫成

Foo* foo = Log(__FILE__, __LINE__, new (whatever) Foo);

的形式即可。但在這個形式里,我們沒法用#define new的方法插入『分號前面的右括弧』。那麼,我們不要用像Log()這樣的『一般的函數調用』的形式,而是改寫成『運算符重載調用』的形式,就可以省去這個右括弧了。由於需要選擇一個優先順序正確的運算符,以及考慮到不常用性,上面的實現選用了-&>*這個運算符。


推薦閱讀:

C++ unordered_map 中 double 作key如何在模板參數中實現?
C++派生類的成員或友員只能通過派生類對象來訪問基類的受保護成員?
C++ 11會帶來什麼影響?
Mac系統下最好用的C++ IDE是XCode嗎 ?
c++虛函數表在運行時候是如何存在的?

TAG:C | VisualC |