5

注意:为了澄清,问题不是关于restrict关键字的一般使用,而是具体关于将其应用于成员函数,如此处所述

gcc 允许您在成员函数上使用__restrict__(相当于 C99 的 GNU++ restrict)限定符,有效地this在函数范围内创建一个限制限定指针。牛肉在哪里?

大多数成员函数在其他成员上工作,通过 访问它们this,这是一个T* const(并且通常是无别名的)。为了this可能被别名,需要在成员函数中以某种方式使用第二个指向类型的指针,并且它必须来自某个地方。
这是非成员函数经常出现的情况,例如所有二元运算符或任何其他自由函数,它们至少需要两个相同的非平凡类型的指针或引用。但是,这些函数没有 a this,因此它们不相关。

赋值运算符、复制构造函数和一元比较运算符是原则上可以使用别名的成员函数的示例this 因为另一个对象是通过引用传递的)。因此,为这些分配一个限制限定符才真正有意义——编译器应该已经很明显所有其他函数都具有限制属性(因为从来没有第二个指向 T 的指针)。

现在,例如,如果您使用restrictonoperator=您应该因此根本不检查自分配,因为您说的this是在该函数的范围内没有别名(如果这是真的,则不可能发生自分配)。
显然,这是你不可能事先知道的事情,也是没有意义的事情。

那么,在什么情况下,人们实际上想要给成员函数一个限制限定符,并且它在哪里有意义?

4

5 回答 5

4

要么我遗漏了一些东西,要么你的问题没有意义。 this与成员函数的任何其他参数没有什么不同,那么为什么您会对 GCC 允许您应用restrict它感到惊讶呢?

关于将其应用于赋值运算符,您正确地指出它将消除对显式自赋值测试的需要。然后你说:

显然,这是你不可能提前知道的事情

但是,当您用于任何事情时,这始终restrict是正确的。例如,有人可能决定memcpy使用重叠的内存区域进行调用;你“不可能提前知道”他们不会这样做。但是,如果他们这样做,则声明restrict他们已经犯了错误。以完全相同的方式,如果您声明了一个赋值运算符,您就会使某人自分配该类的对象成为错误。这一点一点也不神秘或矛盾。它只是语义的一部分,它对您的其余代码施加了某些限制。memcpyrestrictrestrict

我也不确定为什么你发现成员函数不可能将指针(或引用)指向另一个相同类型的对象。简单的例子:

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

这种事情时时冒出来。

所以真正的问题是,为什么你认为this与其他任何论点如此不同?或者,如果您愿意,我怎么会完全错过您的观点?

于 2011-07-25T05:23:24.347 回答
2

我相信你们缺少的是成员函数的参数也可以别名部件或对象。这是一个例子

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

which is obviously way less efficient. Note that unless compute_something is inlines, the compiler has no way of knowing whether result may alias some_value or not, so it has to assume the worst case, no matter no smart or dumb it is. So there a definite and very real advantage to restrict, even if applied to the this pointer.

于 2012-04-21T23:57:01.357 回答
1

您发布的链接很有趣。应用restrictthis. 正如您在问题中提到的,复制构造函数 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;

尽管这是非常不寻常的做法,但这是我能想到的唯一用例。

于 2011-07-25T03:58:19.163 回答
0

恐怕我不清楚你在说什么this

restrict指定一个指针不与其他指针重叠。因此,编译器可以假设限制指针指向的内存区域是不相关的,这允许更积极的优化。__restrict__当用于其他指针变量时会比this.

那么,在什么情况下,人们实际上想要给成员一个限制限定符,并且它在哪里有意义?

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

void Foo::MyCompute(__restrict__ char* bufA, __restrict__ char* BufB)
{
}
于 2011-07-24T17:56:46.093 回答
0

添加这个作为答案,因为它可能更适合这样(它是一种答案,并不真正属于问题,而且评论有点长)。

想了很久尼莫的回答,我相信我们对自我分配的两种解释可能有些错误(尽管尼莫的比我的更正确)。正如 Nemo 正确指出的那样,具有限制条件this实际上意味着存在别名是程序错误。不多也不少。

就目前而言,在编写本文时,您的逻辑实际上不应该是“因为您说这不会发生,因此您不应该检查自分配”,而是“因为您明确表示不会发生别名,如果它是程序错误确实,您不仅需要检查自我分配,而且如果发生这种情况,您因此必须努力失败”。

而且,就目前而言,它强调了特定的程序逻辑,同时允许编译器针对特定的特殊情况进行更好的优化,因此确实有意义

于 2011-07-25T12:11:39.147 回答