簡體   English   中英

限制成員函數的限定符(限制此指針)

[英]restrict qualifier on member functions (restrict this pointer)

注意:為了澄清,問題不是關於一般使用restrict關鍵字,而是關於將其應用於此處所述的成員函數。

GCC允許您使用的__restrict__ (GNU的++相當於C99的restrict )限定符上的成員函數,有效地使this一限制的功能的范圍內合格指針。 牛肉在哪里?

大多數成員函數上的其他成員的工作,通過訪問它們this ,這是一個T* const (和通常非混淆)。 為了使this可能是別名,需要在成員函數中以某種方式使用第二個指向類型的指針,並且它必須來自某個地方。
這種情況通常是非成員函數的情況,例如所有二元運算符或任何其他自由函數,其取至少兩個指針或相同的非平凡類型的引用。 但是,這些功能沒有this ,因此它們不相關。

賦值運算符,拷貝構造,和一元比較運算符,其中成員函數實例this原則上可以別名(因為另一個目的通過引用傳遞)。 因此,為這些分配限制限定符才真正有意義 - 編譯器應該已經明白所有其他函數都具有restrict屬性(因為從來沒有第二個指針指向T)。

現在,例如,如果你使用的restrictoperator=你應該必然不會檢查自賦值可言,因為你說this是不是該函數的范圍內的別名( 如果這是真的 ,沒有自我分配可以可能發生)。
顯然,這是你事先不可能知道的事情,而且這也是沒有意義的事情。

那么,實際上想要給成員函數一個限制限定符以及它有意義的情況會是什么情況呢?

我錯過了什么,或者你的問題沒有意義。 this與成員函數的任何其他參數沒有什么不同,那么為什么GCC允許您對其應用restrict感到驚訝?

關於將它應用於賦值運算符,您正確地指出它將消除對顯式自賦值測試的需要。 然后你說:

顯然,這是你事先不可能知道的事情

但是當你對任何東西使用restrict時,這總是正確的。 例如,某人可能決定調用具有重疊內存區域的memcpy ; 你“不可能提前知道”他們不會這樣做。 但是memcpy參數的restrict聲明意味着如果他們這樣做,他們就會犯錯誤 以完全相同的方式,如果您聲明賦值運算符restrict ,則表示某人自行分配該類的對象是錯誤的。 這根本沒有什么神秘或矛盾的; 它只是restrict語義的一部分,它對代碼的其余部分施加了某些約束。

我也不確定為什么你發現成員函數不可能將指針(或引用)帶到同一類型的另一個對象上。 瑣碎的例子:

class Point {
public:
    double distance(const Point &other) const;
};

這種事情一直在增加。

所以真正的問題是,為什么你認為this與其他論點有如此不同? 或者如果你願意,我怎么完全錯過了你的觀點?

我相信你們缺少的是成員函數的參數也可以是部分或對象的別名。 這是一個例子

struct some_class {
    int some_value;

    void compute_something(int& result) {
        result = 2*some_value;
        ...
        result -= some_value;
    }
}

人們可能希望編譯到

*(this + offsetof(some_value)) -> register1
2*register1 -> register2
...
register2 - register1 -> result

遺憾的是,如果有人將some_value的引用傳遞給結果,那么該代碼將是錯誤的 因此,編譯器實際上需要生成以下內容

*(this + offsetof(some_value)) -> register1
2*register1 -> register2
register2 -> result

...
*(this + offsetof(some_value)) -> register1
result -> register2
register2 - register1 -> register2
register2 -> result

這顯然效率低下。 請注意,除非compute_something是內聯的,否則編譯器無法知道結果是否可能是some_value的別名,因此它必須假設最壞的情況,無論是聰明還是愚蠢。 因此,即使應用於this指針,限制也有明確且非常明顯的優勢。

您發布的鏈接很有趣。 沒有堅實的用例來restrict應用this restrict 正如您在問題中提到的, 復制構造函數,operator =可能是潛在的候選者; 但編譯器可以處理它們。

但以下案例可能很有趣

struct A
{
  //...
  void Destroy (A*& p) __restrict__
  {
    delete this;
    p = 0;
    p++;
  }
};

現在用例可以;

A **pp = new A*[10];
for(int i = 0; i < 10; i++)
  pp[i] = new A;
//...
A* p = pp[0];
for(int i = 0; i < 10; i++)
  p->Destroy(p);
delete[] pp;

雖然這是非常不尋常的做法,但這是我能想到的唯一一個用例。

我擔心我不明白為什么你在談論this

restrict指定指針不與其他指針重疊。 因此,編譯器可以假設限制指針指向的內存區域不依賴,這允許更積極的優化。 __restrict__用於比其他指針變量的時候會更加有效this

那么,如果一個人真的想給一個成員一個限制限定符並且它有意義呢?

回想一下在memcpy中使用restrict指針的代表性案例:

void Foo::MyCompute(__restrict__ char* bufA, __restrict__ char* BufB)
{
}

添加這個作為答案,因為它可能更適合這樣(它是一種答案,並不真正屬於問題,加上評論有點長)。

在考慮了Nemo的答案很長一段時間之后,我相信我們對自我任命的兩種解釋可能都有些錯誤(盡管Nemo比我的更正確)。 正如Nemo正確指出的那樣,具有限制限定this實際上意味着存在別名是一個程序錯誤。 不多也不少。

在寫這篇文章的時候,你的邏輯實際上應該不是“因為你說這不會發生,你因此不應該檢查自我分配”,而是“因為你明確地說別名不能發生,而且如果它是一個程序錯誤你不僅需要檢查自我分配,而且如果發生這種情況,你必須努力工作。“

而且,就此而言,它強調特定的程序邏輯,同時允許編譯器針對特定的特殊情況進行更好的優化,因此確實有意義

暫無
暫無

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

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