假設我有一個是這樣定義的調試功能:調試功能「消失」在某些情況下
namespace debug {
void report(std::string message);
}
我能拉一些編譯器技巧,將編譯的時候,安全與nop
代替每個呼叫。我不想調用一個空函數,我不想調用函數。
如果有可能......我可以讓命名空間「消失」嗎?
調試可執行文件將被編譯爲符號DEBUGEXECUTABLE
定義(我可以想象一些宏的技巧)。
假設我有一個是這樣定義的調試功能:調試功能「消失」在某些情況下
namespace debug {
void report(std::string message);
}
我能拉一些編譯器技巧,將編譯的時候,安全與nop
代替每個呼叫。我不想調用一個空函數,我不想調用函數。
如果有可能......我可以讓命名空間「消失」嗎?
調試可執行文件將被編譯爲符號DEBUGEXECUTABLE
定義(我可以想象一些宏的技巧)。
你可以做這樣的事情:
namespace debug
{
void report(std::string message); // ToDo - define this somewhere
}
namespace release
{
template <class Y>
void report(Y&&){} // Intentionally do nothing
}
#if defined(DEBUGEXECUTABLE)
namespace foo = debug; // set foo to the debug namespace
#else
namespace foo = release; // set foo to the release namespace
#endif
然後在你的代碼中使用foo::report
。我喜歡這個,因爲它最大限度地減少了預處理器宏的使用,並且在調試和發佈配置中保持了大致相似的編譯器錯誤。
在釋放模式下傳遞r值參考將允許編譯器優化任何匿名臨時對象。對於調試家庭的功能,你應該不斷引用傳遞一個字符串,雖然避免的值複製任何方法可行採取:void report(const std::string& message);
這仍然是一個'std :: string'副本。試試'template
不足 - 'report(「hello」)'不應該在release中分配。 – Yakk 2014-12-04 16:20:52
我喜歡命名空間的想法,我想我會從@Mateusz Drost(+引用)的內聯技巧。我會在明天objdump結果並告訴你gcc-4.8是否優化它。 – WorldSEnder 2014-12-04 16:33:35
namespace debug {
#ifdef DEBUGEXECUTABLE
void report(std::string message);
#else
inline void report(std::string message)
{
//nop - compiler should optimize it
}
#endif
}
'report(「hello」)'在你的發佈版本中導致分配。編譯器不太可能優化它。 – Yakk 2014-12-04 16:23:32
1)大多數編譯器會優化它,除非你設置O0 2)如果你設置00你不關心nonoptimise分配;) 3)但如果你關心,那麼只需使用const std :: string&和const char * 4)我只是使用問題 – 2014-12-04 16:29:27
- 1的聲明:[不,你是不正確的](http://goo.gl/uSzFsn) - 刪除分配不是一個微不足道的行爲,並沒有遵循as-if規則。 – Yakk 2014-12-04 16:34:59
這是最佳的,因爲我可以把它。
我們定義DEBUG
有report
,做什麼,離開它,它什麼都不做(或者我們可以使用您使用在構建過程中的任何符號來區分調試和生產代碼選擇)
#define DEBUG
我們創建了兩個名稱空間。一個叫debug
,另一個叫release
。在每一個我們創建了一個匿名的命名空間,這很容易讓編譯器來檢測和丟棄不用的功能:
namespace debug {
namespace {
void report(std::string const& s) {
std::cerr << s << "\n"; // sample implementation
}
}
}
namespace release {
namespace {
template<class T>
void report(T&&) {} // Or `class...Ts` and `Ts&&...` to handle more than 1 argument optionally.
}
}
這裏我們創建一個命名空間的別名,在發行和調試不同:
#ifdef DEBUG
namespace report=debug;
#else
namespace report=release;
#endif
而且我們的主:
int main() {
report::report("hello");
}
我們可以在在看到該下GCC 4.9的結果與DEBUG
defined和。正如你所希望的那樣,當#define DEBUG
沒有被定義時,編譯器只產生一個空的main
。
如果定義了它,它將編譯爲您所期望的。
因爲我學習了新的東西,所以我想加倍努力。 ('namespace ... = ...;') – LyingOnTheSky 2014-12-04 16:46:18
請注意,調用一個空函數會導致編譯器轉到「嘿,爲什麼我要調用一個空函數?」,並優化調用。因此,爲什麼大多數答案顯示使用宏來調用非調試版本中的空函數。 – KidneyChris 2014-12-04 16:15:45