[英]In C++, can I declare a reference so as to indicate that nothing will ever modify it?
如果我做
typedef void Cb();
int foo(int const& a, Cb cb) {
int x = a;
cb();
return x - a;
}
並使用g++ -O3 -save-temps -c foo.cpp
,我看到減法被保留,而如果cb();
被注釋掉,整個函數優化到
xorl %eax, %eax
我可以對參數a
的規范做些什么,這樣無論對cb()
的調用如何都不會優化減法,並且不強制a
成為唯一引用(即,它可以在別處引用,但通過這些參考文獻都不會被修改)?
執行建議的優化是不正確的,因為其余代碼可能是:
static int var;
void func()
{
var++;
}
// ...
foo(var, func);
我不知道你可以設置任何特定於編譯器的屬性來說cb()
不會修改a
。
有__restrict
擴展名,你可以在gcc.godbolt.org上試試這個:
typedef void Cb();
int foo(const int & __restrict a, Cb cb) {
int x = a;
cb();
return x - a;
}
奇怪的是, 只有clang進行優化 , gcc不會這樣做 。
請注意,類似限制的別名被認為是C ++標准的一部分:
也許將來你可以通過標准來做到這一點。
為什么不移動int x = a;
函數調用下面的行?
如果cb()
既不影響x
也不影響a
,你應該沒問題,我認為編譯器會再次優化調用,因為x不能在兩次調用之間改變。 如果您無法重新排序這兩個調用,則可能無法首先對其進行優化。
這不是你可以暗示編譯器要做的事情,因為在調用cb()
之后無法保證x和a都沒有改變。
將此視為讀/寫訪問的順序 。 如果在cb()
期間沒有對a
和x
讀或寫訪問,則可以手動重新排序函數調用。
如果a
或x
寫的是你不能重新排序和優化將是不正確的。
如果x
被讀取,你不能重新排序的函數調用,但如果x
確實是只讀的,你可以從一個而不是閱讀,並定義x
僅在調用之后,因為它將具有相同的值作為a
曾在你面前宣布它呼叫。
如果編譯器支持該擴展,則可以在引用上使用C restrict
。
(某些編譯器允許__restrict
或__restrict__
,它們是implements命名空間的一部分。)
這是您向編譯器的承諾,即對象在任何地方都沒有別名,因此可以對其進行優化。
如果你對編譯器撒了謊,那么你就得到了你應得的破解代碼。
__attribute __((const))就足夠了
如下所述: https : //gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Function-Attributes.html ,它告訴編譯器給定的函數不修改全局變量(雖然它可以讀取它們)。
還有const
的pure
子集,它也禁止全局讀取。
請考慮以下簡化示例:
int __attribute__((const)) g();
int f(int a) {
int x = a;
g();
return x - a;
}
在g++
4.8 x86_64 -O3
,它編譯為:
xor %eax,%eax
with const
const
的大型函數,不假設a
不被修改 似乎沒有更細粒度的屬性表示函數不會根據需要修改給定變量。
__attribute __((const))可以應用於函數指針嗎?
我們試試吧:
int f(int& a, void __attribute__((const)) (*g)(void)) {
int x = a;
(*g)();
return x - a;
}
再次,它編譯為xor %eax,%eax
,以及沒有const
的大函數,所以答案是肯定的。
這個語法是在: 函數指針__attribute __((const))函數?
它也出現在2011年的郵件列表上: http : //comments.gmane.org/gmane.comp.gcc.help/38052至少在當時它只適用於某些屬性。
可以將__attribute __((const))添加到typedef嗎?
這有效:
typedef void __attribute__((const)) (*g_t)(void);
int f(int& a, g_t g) {
int x = a;
(*g)();
return x - a;
}
要么:
typedef void (g_t)(void);
int f(int& a, g_t __attribute__((const)) g) {
int x = a;
g();
return x - a;
}
但我無法找到一種方法將屬性放在typedef上並傳遞函數,而不是指針,如:
typedef void __attribute__((const)) (g_t)(void);
GCC發出警告說在這種情況下該屬性被忽略了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.