[英]C++ optimization of reference-to-pointer argument
我想知道以下函數是否使用臨時變量(p):
void parse_foo(const char*& p_in_out,
foo& out) {
const char* p = p_in_out;
/* Parse, p gets incremented etc. */
p_in_out = p;
}
還是我可以只使用原始參數,並希望它與上述方法類似地被優化? 似乎應該進行這樣的優化,但是我已經在Mozilla的代碼之類的一些地方看到了上述優化,並對“避免別名”的注釋模糊不清。
所有好的答案,但是如果您擔心性能優化,那么實際的解析將花費幾乎所有時間,因此指針別名可能會“陷入困境”。
帶有臨時變量的變體可能更快,因為這並不意味着對指針的每次更改都會反映回參數,並且編譯器更有可能生成更快的代碼。 但是,測試此問題的正確方法是編譯並查看反匯編。
同時,這與避免混疊有關。 實際上, 帶有臨時變量的變量確實使用了別名-現在您在同一數組中有兩個指針,這正是別名。
如果該功能具有事務性,我將使用臨時方法。
即功能成功或完全失敗(沒有中間立場)。
在這種情況下,我將使用臨時函數在函數執行時保持狀態,並且僅在函數成功完成后才分配回in_out參數。
如果函數過早退出(即通過異常退出),那么我們有兩種情況:
我看不到任何一種方法的優化優勢。
是的,您應該將其分配給標記為restrict
(在MSVC中為__restrict
)的本地。
這樣做的原因是,如果編譯器不能完全確定范圍中的其他指針是否指向p_in_out
,則它無法將指針下的內容存儲在本地寄存器中。 每次您寫入同一作用域中的任何其他char *
,它都必須回讀數據。 這是否是“智能”編譯器都不成問題; 這是正確性要求的結果。
通過編寫char* __restrict p
可以向編譯器保證, 沒有其他指針與p指向相同的地址 。 沒有此保證, *p
的值可以在每次寫入任何其他指針時更改,或者每次寫入*p
時它可能更改其他指針的內容。 因此,編譯器必須*p
每個分配立即寫回內存,並且在每次寫入另一個指針后必須將其讀回。
因此,保證編譯器不會發生這種情況 -它可以只加載一次*p
並且假定沒有其他指針會影響它-可以改善性能。 究竟多少取決於特定的編譯器和情況:在處理器上,要承受按負載加載的懲罰,這是巨大的; 在大多數x86 CPU上,它是適中的。
在這里偏愛使用指針指向引用的原因僅僅是因為可以將指針標記為restrict
而引用則不能。 這就是C ++的方式。
您可以嘗試兩種方法,然后測量結果以查看哪種方法確實更快。 而且,如果您感到好奇, 我會在其他地方深入討論restrict
和負載均衡存儲 。
附錄 :寫完上面的內容后,我意識到Moz的人們更擔心引用本身會被別名化-也就是說,其他內容可能指向存儲const char *p
的同一地址,而不是指向存儲該字符的char p分。 但是我的回答是相同的:在幕后, const char *&p
表示const char **p
,並且與其他任何指針一樣,也存在相同的別名問題。
編譯器如何知道p_in_out沒有以某種方式別名? 確實無法優化通過引用回寫數據的過程。
struct foo {
setX(int); setY(int);
const char* current_pos;
} x;
parse_foo(x.current_pos, x);
我看了一下,問為什么不只返回指針呢?那么您就沒有對指針的引用,也不必擔心修改原始指針了。
const char* parse_foo(const char* p, foo& out) {
//use p;
return p;
}
這也意味着您可以使用右值調用該函數:
p = parse_foo(p+2, out);
立即想到一個想法:異常安全。 如果在解析過程中引發異常,則應使用臨時變量來提供強大的異常安全性:函數調用已完全成功或沒有執行任何操作(從用戶角度而言)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.