2011-03-07 109 views
9

當在C++頭文件中有一個靜態全局變量時,包含頭文件的每個翻譯單元都以其自己的變量副本結束。內聯成員函數使用的靜態全局變量

然而,如果我聲明在同一標題文件中的類,並創建一個類的成員函數,類聲明中的內聯實現,它使用靜態全局變量,例如:

#include <iostream> 

static int n = 10; 

class Foo { 
public: 
    void print() { std::cout << n << std::endl; } 
}; 

然後我看到下的gcc 4.4略微古怪的行爲:

  1. 如果我編譯不優化,成員函數的所有用途中使用該變量的副本從翻譯單元中的一個(上g ++命令提到的第一個線)。

  2. 如果我使用-O2進行編譯,每次使用成員函數都會使用來自作出該事件的翻譯單元的變量副本。

顯然這是非常糟糕的設計,所以這個問題只是出於好奇。但是,我的問題是,C++標準對這種情況說了些什麼? g ++是否通過在啓用和未啓用優化的情況下提供不同的行爲來正確行爲?

+1

可能的重複:[h文件和內部鏈接中的靜態關鍵字](http://stackoverflow.com/questions/4276794/static-keyword-in-h-file-and-internal-linkage)。 – 2011-03-07 11:49:33

回答

12

的標準說(3.2/5):一類型的

可以有多於一個的定義 (第9節), ...提供的定義滿足 以下要求.. 。在d中的每個 定義,相應的名稱, 擡頭根據3.4,應 指d的定義 內定義一個實體,或應指 同一實體

這是您的代碼丟失的地方。 nFoo的不同定義中的用法不涉及相同的對象。遊戲結束,未定義的行爲,所以是gcc有權在不同的優化級別做不同的事情。

3.2/5繼續:

不同之處在於一個名稱可以指 const對象與內部或沒有 聯動如果對象具有相同的 整數或枚舉類型d的所有 定義,並且對象 以恆定表達 (5.19),並且該值被初始化(但不是 地址)所述對象的使用,和 對象具有在d

的所有 定義相同的值

因此,在您的示例代碼中,您可以將n設置爲static const int,並且所有這些都很可愛。本條款描述的條件並不是巧合,不同的TU是指「相同的對象還是不同的對象 - 它們所使用的全部是編譯時常量值,它們都使用相同的值。

+1

+1:有時會以非常微妙的方式違反ODR – 2011-03-07 11:33:18

+0

優秀的答案。謝謝。 – jchl 2011-03-07 12:30:38