簡體   English   中英

將const放在標題中

[英]Putting a const in a header

從我正在閱讀和測試的所有內容中,沒有辦法(沒有預處理器宏)在共享頭中定義常量,並確保每個TU不為該常量創建自己的存儲。

我可以做這個:

const int maxtt=888888;

這完全相同:

static const int maxtt=888888;

如果此標頭是共享的,它將起作用,但每個TU都有自己的maxtt副本。 我也可以這樣做,以防止:

extern const int maxtt;

但是我不能在這里定義maxtt ; 必須在CPP中完成,以避免鏈接器錯誤。

我的理解是否正確?

由於變量是常量,因此每個TU獲得自己的副本的事實通常是無關緊要的。

在C ++中,由於這個原因,命名空間范圍內的常量是隱式static的。 通常這允許更好的代碼,而不是只有一個具有外部鏈接的單個實例,因為(如果變量實際上是一個常量表達式),常量通常可以直接折疊到使用站點中,並且根本不需要存儲。

因此,除非你真的需要獲取常量的地址,或類似的東西,你應該堅持使用靜態版本。 (正如你已經看到,您可以通過添加強制外部鏈接extern 。)另一個原因可能是,你動態初始化和只想要一個調用初始化:

// header:
extern int const n;

// one implementation:
int const n = init_function_with_side_effects();

靜態構造(標頭中的int const n = init();將導致在每個TU中調用一次函數。

你寫,

“從我正在閱讀和測試的所有內容中,沒有辦法(沒有預處理器宏)在共享頭中定義一個常量,並確保每個TU不為該常量創建自己的存儲。”

幸運的是,這是不正確的

對於小的積分值,您始終只需使用enum 權衡是你不能傳遞enum值的地址,因為它沒有地址。 這是純粹的價值。

但是,為整數值節省空間是一件非常無意義的事情,因為它太小了。

所以,讓我們考慮一個大事,

struct BiggyThingy
{
    unsigned char zeroes[1000000];
    BiggyThingy(): zeroes() {}
};

現在我們如何在頭文件中聲明一個BiggyThingy常量並確保整個程序的整體常量?

使用內聯函數。

最簡單的是:

inline BiggyThingy const& getBiggyThingy()
{
    static BiggyThingy const theThingy;
    return theThingy;
}

static BiggyThingy const& biggyThingy = getBiggyThingy();

如果您不希望每個轉換單元中的引用占用空間(如指針),則只需使用不帶符號簡化引用的函數。

使用模板常量技巧。

這是提供常量的另一種方法,而是利用模板的特殊規則:

template< class Dummy >
class BiggyThingyConstant_
{
public:
    static BiggyThingy const value;
};

template< class Dummy >
BiggyThingy const BiggyThingyConstant_<Dummy>::value;

typedef BiggyThingyConstant_<void> BiggyThingyConstant;

可以像訪問一樣訪問

foo( BiggyThingyConstant::value )

或者,如果您需要更好的表示法,則可以為每個翻譯單元添加一個引用,就像內聯函數解決方案一樣。

免責聲明:

代碼未受編譯器影響。

但我認為你會得到這些想法。 ;-)

僅當您應用任何需要常量地址的操作時,此代碼才會在TU中生成常量。

static int maxtt = 888888;
int * pmaxtt = &maxtt; //address of constant requested.

這也可以工作並避免鏈接器問題(盡管如果請求地址, maxtt在每個TU中存儲maxtt ):

constexpr int maxtt = 888888;

避免extern結構,因為它無法優化。

如果您對存儲非常擔心,請使用枚舉:

enum { maxtt = 888888 };

枚舉器是標量右值,因此不需要存儲。 &maxtt是違法的。

實際上,您對語義的理解是正確的。

實際上,每個翻譯單元可能無法獲得整數的存儲副本。 一個原因是編譯器可能會將值實現為文本,只要它被引用。 鏈接器也可能足夠聰明,如果發現它未被引用,則丟棄該存儲。

編譯器可能無法為常量使用文字。 您可以引用該整數,或獲取指向它的指針。 在這種情況下,您需要存儲 - 您甚至可能需要交叉compiland唯一性。 如果在每個編譯單元中獲取const符號的地址,您可能會發現它的不同,因為每個對象都將獲得唯一的靜態副本。

如果使用枚舉,可能會遇到類似的問題; 你的const int有存儲空間,你可以獲取該存儲的地址。 在將其存儲到某個位置之前,您無法獲取枚舉的地址。

暫無
暫無

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

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