[英]Is putting const before and after a function header equivalent?
[英]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.