繁体   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