2011-05-01 109 views
99

在我們所有的C++課程中,所有教師總是在其.h文件的#include之後立即放置using namespace std;。這在我看來是危險的,因爲通過在另一個程序中包含該頭文件,我會將名稱空間導入到我的程序中,也許沒有意識到,打算或想要它(頭文件包含可以非常深入地嵌套)。「在C++頭文件中使用命名空間」

所以我的問題是雙重:我是正確的,using namespace不應該在頭文件使用,並且/或者是有一些辦法撤消它,像:

//header.h 
using namespace std { 
. 
. 
. 
} 

一個沿着相同的多個問題行:如果一個頭文件#include它對應的所有頭文件需要.cpp文件,那麼只有那些頭文件定義需要的頭文件,並且讓其餘的文件或者其他文件不需要,並且將它需要的所有東西聲明爲extern
問題背後的原因與上面相同:包含.h文件時,我不希望出現意外。

另外,如果我是對的,這是一個常見的錯誤?我的意思是在現實世界的編程和那裏的「真實」項目中。

謝謝。

+3

http://stackoverflow.com/questions/1265039 /使用-STD-命名空間 – 2011-05-01 15:53:12

+2

作爲一個側面說明,如果你的名字的衝突,由於'使用namespace'語句,那麼你可以使用完全合格的名稱來解決這個問題。 – 2011-05-01 16:08:04

回答

87

您絕對不應該在標頭中使用using namespace,這正是您說的原因,它可以意外更改包含該標頭的任何其他文件中代碼的含義。無法撤銷using namespace,這是另一個非常危險的原因。我通常只是使用grep或類似的方法來確保using namespace不是在頭文件中調用,而是嘗試任何更復雜的事情。也許靜態代碼檢查器也會標記這一點。

頭文件應該只包含它需要編譯的頭文件。執行此操作的一種簡單方法是始終在每個源文件的頭部之前包含每個源文件的頭部。如果頭文件不是獨立的,那麼源文件將無法編譯。在某些情況下,例如引用庫中的實現細節類,您可以使用前向聲明而不是#include,因爲您可以完全控制此類前向聲明​​類的定義。

我不確定我會把它叫做通用的,但它一定會偶爾出現,通常是由不知道負面後果的新程序員寫出來的。通常只要對風險進行一點教育就可以解決任何問題,因爲修復起來相對簡單。

4

你說得對。任何文件都應該只包含該文件所需的頭文件。至於「是否在現實世界的項目中做錯了常見的事情?」 - 哦,是的!

5

你是對的,using namespace在標題是危險的。 我不知道如何撤消它。 它很容易檢測到,但只是在頭文件中搜索using namespace。 由於最後一個原因,它在實際項目中並不常見。如果有人做了類似的事情,更有經驗的同事很快就會抱怨。

在真實項目中,人們儘量減少包含文件的數量,因爲包含的文件越少,編譯的速度越快。這節省了大家的時間。但是,如果頭文件假定在它之前應該包含某些內容,那麼它應該包含它自己。否則,它會使標題不是自包含的。

12

將標題包含在標題中時需要注意。在大型項目中,它可以創建一個非常糾結的依賴鏈,從而觸發比實際需要的更大/更長的重建。查看this articleits follow-up瞭解更多關於良好物理結構在C++項目中的重要性。

當絕對需要時(無論何時需要完整定義類),只應在頭中包含頭文件,並且在需要的類是指針或引用時使用前向聲明。對於命名空間,我傾向於在我的頭文件中使用顯式命名空間範圍,並且只在我的cpp文件中放置了一個using namespace

+2

+1,以儘可能強調前向聲明。 – 2011-05-01 20:25:47

3

像編程中的所有事情一樣,實用主義應該贏得教條主義,IMO。

只要你在項目範圍內做出決定(「我們的項目廣泛使用STL,而且我們不想用std ::來預先設置所有東西)」,但是我沒有看到它的問題。畢竟,冒着唯一的風險就是名稱衝突,並且隨着STL的無處不在,這不太可能成爲問題。另一方面,如果這是一個開發人員在單個(非私人)頭文件中做出的決定,我可以看到它會如何在團隊間產生混淆,因此應該避免。

20

項目59薩特和Alexandrescu的的「C++編程規範:101條規則,準則和最佳實踐」:

  1. Don’t write namespace usings in a header file or before an #include. 108

的所有準則標題是在http://www.gotw.ca/publications/c++cs.htm,但細節必讀適用於C++開發人員。

6

查看戈達德太空飛行中心編碼標準(適用於C和C++)。這原來是比它曾經是有點困難 - 看到更新後的答案,做題:

的戈達德空間飛行中心的C++編碼規範說:

§3.3.7 Each header file shall #include the files it needs to compile, rather than forcing users to #include the needed files. #includes shall be limited to what the header needs; other #includes should be placed in the source file.

第一個交叉引用的問題現在包括GSFC C編碼標準的引用和基本原理,但實質結果是bei相同。

2

我相信你可以在C++頭文件,如果你寫的聲明在一個嵌套命名空間像這樣使用「使用」安全:

namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED 
{ 
    /*using statements*/ 

    namespace DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED 
    { 
     /*declarations*/ 
    } 
} 

using namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED::DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED; 

這應該只包括不使用的命名空間中「DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED」聲明的東西。我已經在mingw64編譯器上對它進行了測試。

+0

這是一個我以前從未見過的有用技巧;謝謝。通常情況下,我已經使用完整範圍限定條件,並且在函數定義內部放置'using'聲明,以便它們不會污染函數外部的命名空間。但是現在我想在頭文件中使用C++ 11用戶定義的文字,並且按照慣例,文字操作符受命名空間保護;但我不想在構造函數初始化列表中使用它們,這些列表不在我可以使用無污染的'using'聲明的範圍內。所以這對解決這個問題非常有用。 – 2016-12-17 06:24:05

+0

雖然這種模式的一個不幸的副作用是最裏面的命名空間內聲明的類將與全名編譯器錯誤信息顯示:'錯誤:... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED :: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED ::類名...'。至少,這就是我在g ++中發生的事情。 – 2016-12-17 07:03:13

2

關於「是否有某種方法可以撤消[a using聲明]?」

我認爲指出using聲明受範圍影響很有用。

#include <vector> 

{ // begin a new scope with { 
    using namespace std; 
    vector myVector; // std::vector is used 
} // end the scope with } 

vector myOtherVector; // error vector undefined 
std::vector mySTDVector // no error std::vector is fully qualified 

所以有效的是的。通過限制聲明的範圍,其效果僅在該範圍內持續;當範圍結束時它是'撤消'的。

using聲明聲明文件中的任何其他範圍外有文件範圍和影響在該文件中的一切。

在頭文件的情況下,如果using聲明是在文件範圍,這將延伸到頭部被包括在任何文件的範圍。

+0

你似乎是唯一一個瞭解實際問題的人......但是,我的編譯並不是很高興我在課堂減速中使用。 – rustypaper 2017-01-08 16:34:58