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++虛函數表在運行時候是如何存在的?