C++ 限制成员函数上的限定符(限制此指针)

C++ 限制成员函数上的限定符(限制此指针),c++,gcc,this-pointer,restrict-qualifier,C++,Gcc,This Pointer,Restrict Qualifier,注意:为了澄清,问题不在于一般情况下如何使用restrict关键字,而在于如何将其应用于所述的成员函数 gcc允许您在成员函数上使用\uuuuu restrict\uuuuu(GNU++相当于C99的restrict)限定符,有效地使此成为函数范围内的限制限定指针。牛肉在哪里 大多数成员函数在其他成员上工作,通过this访问它们,this是T*const(通常是无关联的)。若要使此具有别名,则需要有第二个指针指向成员函数中正在使用的类型,并且它必须来自某个地方。 这是非成员函数经常出现的情况,例

注意:为了澄清,问题不在于一般情况下如何使用
restrict
关键字,而在于如何将其应用于所述的成员函数

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

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

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

现在,如果您在
操作符=
上使用了
restrict
,那么您不应该检查自赋值,因为您是说
在该函数的范围内没有别名(如果这是真的,则不可能发生自赋值)。
显然,这是你不可能事先知道的事情,也是没有意义的事情


那么,在什么情况下,一个人实际上想要给一个成员函数一个限制限定符,以及它在什么情况下是有意义的呢?

恐怕我不太明白你为什么要谈论这个

restrict
指定指针不与其他指针重叠。因此,编译器可以假定限制指针指向的内存区域不依赖,这允许更积极的优化<代码>\uuuu限制\uuuu
用于其他指针变量时比
更有效

那么,在什么情况下,一个人会真正想要给出一个 成员是限制限定符,它在哪里有意义

回想一下在
memcpy
中使用
restrict
指针的典型案例:

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

你发布的链接很有趣。将
限制
应用于
将没有可靠的用例。正如您在问题中提到的,copy constructor,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;
A**pp=新的A*[10];
对于(int i=0;i<10;i++)
pp[i]=新的A;
//...
A*p=pp[0];
对于(int i=0;i<10;i++)
p->Destroy(p);
删除[]页;

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

要么我遗漏了什么,要么你的问题没有意义
与成员函数的任何其他参数没有太大区别,那么为什么您会惊讶于GCC允许您对其应用
限制

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

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

但当您对任何事情使用
restrict
时,这总是正确的。例如,有人可能决定使用重叠的内存区域调用
memcpy
;你“不可能事先知道”他们不会这么做。但是
memcpy
的参数的
restrict
声明意味着如果他们犯了错误,就意味着他们犯了错误。以完全相同的方式,如果声明赋值运算符
restrict
,则会使某人自行分配该类的对象成为错误。这一点都不神秘或矛盾;这只是
restrict
语义的一部分,它对代码的其余部分施加了某些约束

我也不知道为什么一个成员函数不可能获取指向另一个相同类型对象的指针(或引用)。简单的例子:

class Point {
public:
    double distance(const Point &other) const;
};
这类事情经常发生


所以真正的问题是,为什么你认为这个与其他任何论点有如此大的不同?或者,如果你愿意的话,我怎么会完全误解你的观点呢?

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

在考虑了尼莫的答案很长一段时间后,我相信我们对自我分配的两种解释可能都有点错误(尽管尼莫的解释比我的更正确)。正如尼莫正确指出的那样,限制限定的
这实际上意味着存在别名是程序错误。不多也不少

到目前为止,在写这篇文章时,你的逻辑实际上不应该是“既然你说这不可能发生,你就不应该检查自我分配”,而是“既然你明确地说别名不可能发生,如果它发生则是一个程序错误,你不仅需要检查自我分配,而且如果它发生,你必然会失败”

到目前为止,它强调特定的程序逻辑,同时强调
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
*(this + offsetof(some_value)) -> register1
2*register1 -> register2
register2 -> result

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