簡體   English   中英

引用指針參數的C ++優化

[英]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.

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