簡體   English   中英

匿名命名空間內的自由函數

[英]free function inside anonymous namespace

//file.h

namespace Foo{
namespace{
   void func(){}
}
}

VS

namespace Foo{ 
   void func(){} 
}

//file2.cpp use file.h's method

這兩種方法之間的調用代碼(例如,在可見性方面)有什么后果(如果有的話)?

這個:

namespace Foo {
namespace {

void func() {}

}
}

在很大程度上相當於:

namespace Foo {

static void func() {}

}

不同之處在於,在static情況下,函數具有內部鏈接,因此鏈接器不可見。 在未命名的命名空間的情況下,該函數具有外部鏈接(對鏈接器可見),但是在您的其他源文件都不能“正常”訪問的名稱下。 如果您對編譯器的名稱修改方案進行反向工程,您仍然可以從不同的源文件調用該函數,並且該函數仍然列在目標文件的符號中,例如。

但常見的是,每個包含代碼的源文件(可能通過#include the header file)都將包含自己的函數副本。 這可能會影響二進制文件的大小。

此外,如果由於某種原因需要第一個,你應該大量記錄它。 頭文件中的未命名命名空間通常是“WTF”點,您不希望在代碼中使用這些命名空間。 我必須說我想不出一個可行的用例。

兩種變體都允許在名稱Foo::func()下找到該Foo::func()

但是,編譯器可能會在這兩種情況下生成不同的代碼。 在匿名命名空間內聲明一個函數會使該函數成為.cpp文件的本地函數。 也就是說,包含頭部的每個.cpp文件最終可能都有自己的(相同的) func代碼實例化。 由於代碼重復,這可能會導致最終可執行文件中出現一些膨脹。

請注意,如果您定義內聯函數(如您的問題所示),這不是一個真正的問題,因為代碼將因內聯而被復制。

盡管如此,正如評論中所指出的:標題中的匿名名稱空間是不尋常的,並且會引起對此代碼的評論的懷疑。 你應該總是喜歡第二種選擇,除非你有充分的理由不這樣做。

第一個相當於:

namespace Foo
{
    namespace TranslationUnitSpecific
    {
        void func();
    }
}

這意味着每次包含標題時,都會聲明一個新的,不相關的func實例。 如果func不是inline ,則必須在使用它的每個源文件中定義它。 (另一方面,它確實意味着您可以在標題中提供實現而不使函數inline 。)

這也意味着您不能在標題中定義的inline函數或模板函數中使用該函數,因為違反了一個定義規則,存在未定義的行為風險。

通常,如果有任何情況,您應該在標頭中使用未命名的命名空間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM