2015-02-24 94 views
6

有點史前史。nullptr_t駐留在哪裏?

我已經寫了很長一段時間的遊戲引擎。它分爲幾個靜態庫,如「utils」,「rsbin」(資源系統),「窗口」,然後鏈接到一個可執行文件中。

這是一個跨平臺引擎,被編爲Windows和Android版。 在Windows下,我使用MinGW進行編譯。在Android下,使用CCTools,它是本地gcc的接口。

其中一個基類是utils::RefObject,它代表了一個類似於Windows的IUnknown的概念:它提供了一個引用計數器來確定它的生存期以及從基類指針查詢特定接口的方法。還有template< typename T > utils::Ref,專門爲這類物體設計的。它包含一個std::atomic< utils::RefObject* >,並在施工,分配和銷燬時自動更新其對象的重新計數,類似於std::shared_ptr。它還允許通過查詢方法隱式轉換不同類型的RefObjects。雖然,查詢對象的類型是低效的,因此,utils::Ref會重載其大多數運算符,例如, G。有具體utils::Ref<T>::Ref(T* ptr)構造函數,它只是增加了傳遞的對象的引用計數,和一般utils::Ref<T>::Ref(RefObject* ptr),該查詢其對於T的實例論證並拋出失敗異常(不要擔心,雖然,有當然是爲軟鑄的方法)。

但只具有這兩種方法引入了一個問題:你不能明確地用一個空指針初始化utils::Ref,因爲它是不明確的;所以也有utils::Ref<T>::Ref(nullptr_t)提供一種方法來做到這一點。

現在,我們正在解決手頭的問題。在頭文件中,原型與上面拼寫完全一樣,沒有任何前面的std::。請注意,我也不使用using namespace。很長一段時間,這工作。

現在,我正在研究圖形系統。它之前就已經存在,但它是相當基本的,所以我甚至沒有注意到<gl.h>實際上只定義的OpenGL 1.1,而新版本你應該通過<glext.h>。現在,有必要使用後者。但包括它打破了舊的參考類。

從錯誤信息來看,MinGW的現在有在原型,nullptr_t問題。我在網上做了一個快速搜索,發現通常是它被稱爲std::nullptr_t。儘管並非到處都是。

快速sumup:我有沒有nullptr_t無論std::using namespace編譯罰款,直到我包括頭前<glext.h>。

我一直使用至今的網站,cplusplus.com/reference,表明全球::nullptr_tis exactly how it should be。另一方面,en.cppreference.com wiki tells that它實際上是std::nullptr_t

簡單的測試程序,以void foo(int)void foo(nullptr_t)一個HelloWorld,無法編譯,現在的理由是明確的"error: 'nullptr_t' was not declared in this scope"與建議,使用std::nullptr_t代替。

在需要的地方添加std::並不難;但這種情況讓我頗爲好奇。

cplusplus.com實際上在撒謊? =>在回答中回答,是的。這是一個不準確的來源。

然後,如果nullptr_t實際上位於namespace std,爲什麼utils::Ref編譯? =>通過評論中的建議,運行了一些測試,發現<互斥體>,包含在某個其他頭文件中,當放置在任何stddef頭之前時,定義全局爲::nullptr_t。當然不是一個理想的行爲,但它不是一個主要的錯誤。無論如何應該向MinGW/GCC開發者彙報。

爲什麼包含<glext.h>會打破它? =>當<互斥量012xx之前包含任何stddef頭時,該類型根據標準定義爲std::nullptr_t。 <glext.h>包括<windows.h>,它反過來肯定包含stddef頭,其中包含WinAPI需要的其他包。

下面是源,在問題定義的類:

(包括後者2等都可能影響太)

作爲評價建議的,我跑克++ -E在其上編一個測試用例,並且發現了一個很有趣的位在<STDDEF.H>:

#if defined(__cplusplus) && __cplusplus >= 201103L 
#ifndef _GXX_NULLPTR_T 
#define _GXX_NULLPTR_T 
    typedef decltype(nullptr) nullptr_t; 
#endif 
#endif /* C++11. */ 

我們尋找到_GXX_NULLPTR_T被別人定義......快速GREP通過MinGW的的文件,並沒有發現什麼,除了這STDDEF.H

因此,爲什麼以及如何禁用它仍然是個謎。特別是當只包括<stddef.h>而沒有別的沒有定義nullptr_t任何地方,儘管上面的位。

+0

查看預處理輸出以查看引入了':: nullptr_t'的位置。 – tenfour 2015-02-24 13:09:23

+3

FWIW,cplusplus.com因不準確而聞名。 – Angew 2015-02-24 13:14:27

+0

它屬於std,非零的可能性,該源代碼首先看到另一個編譯器首先在頭文件中使用了'std :: nullptr_t;'。像MSVC++一樣。 – 2015-02-24 13:20:03

回答

5

nullptr的類型在命名空間::std中定義,所以正確的限定是::std::nullptr_t。當然,這意味着你在練習中通常拼寫爲std::nullptr_t

引用C++ 11:

2.14.7/1:

指針字面是關鍵字nullptr。這是一種類型std::nullptr_t的價值。

18.2/9:

nullptr_t定義如下:

namespace std { 
    typedef decltype(nullptr) nullptr_t; 
} 

類型爲其nullptr_t是同義詞在3.9.1和4.10中描述的特性。 [注意: 雖然nullptr的地址不能被採取,但作爲左值的另一nullptr_t對象的地址可以採取 。 末端音符]

<stddef.h>也進入圖片。 18.2談到了<cstddef>,所以這是C++頭,其中std::nullptr_t被定義。每D.5/2:

每個C頭,其每一個具有形式name.h的名稱,行爲如同由相應的cname頭放置在標準 庫名稱空間的每個名稱被置於內的全球命名空間範圍。

這意味着包括<stddef.h>可讓您訪問::nullptr_t。但是因爲這應該是C頭文件,所以我建議不要在C++代碼中依賴這個(即使它是正式有效的)。

+0

IMO它說「nullptr」的類型是'nullptr_t'「,而不是''nullptr_t''指定'nullptr'的類型'沒什麼意義。 nullptr_t僅僅是一個typedef。 – Columbo 2015-02-24 13:43:02

+1

考慮到OP現在提到'',可能值得一提的是,該頭文件定義':: nullptr_t'的方式與''定義':: std :: nullptr_t'完全相同。 – hvd 2015-02-24 13:47:54

+0

@Columbo我相信有一個DR,關於這個標準的定義是循環的。 – Angew 2015-02-24 13:49:47