简体   繁体   English

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

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

Note: To clarify, the question is not about the use of the restrict keyword in general, but specifically about applying it to member functions as described here . 注意:为了澄清,问题不是关于一般使用restrict关键字,而是关于将其应用于此处所述的成员函数。

gcc allows you to use the __restrict__ (the GNU++ equivalent to C99's restrict ) qualifier on a member function, effectively making this a restrict qualified pointer within the function's scope. GCC允许您使用的__restrict__ (GNU的++相当于C99的restrict )限定符上的成员函数,有效地使this一限制的功能的范围内合格指针。 Where is the beef? 牛肉在哪里?

Most member functions work on other members, accessing them via this , which is a T* const (and normally unaliased). 大多数成员函数上的其他成员的工作,通过访问它们this ,这是一个T* const (和通常非混淆)。 For this to be possibly aliased, there would need to be a second pointer-to-type in use within the member function somehow, and it would have to come from somewhere. 为了使this可能是别名,需要在成员函数中以某种方式使用第二个指向类型的指针,并且它必须来自某个地方。
That is a situation which is regularly the case with non-member functions, such as for example all binary operators or any other free function that takes at least two pointers or references of an identical, non-trivial type. 这种情况通常是非成员函数的情况,例如所有二元运算符或任何其他自由函数,其取至少两个指针或相同的非平凡类型的引用。 However, these functions don't have a this , so they're not relevant. 但是,这些功能没有this ,因此它们不相关。

The assignment operator, copy constructor, and unary comparison operators are examples of member functions where this could in principle be aliased (since another object is passed via reference). 赋值运算符,拷贝构造,和一元比较运算符,其中成员函数实例this原则上可以别名(因为另一个目的通过引用传递)。 So it only really makes sense to assign a restrict qualifier to these -- it should already be obvious to the compiler that all other functions have the restrict property anyway (because there is never a second pointer-to-T). 因此,为这些分配限制限定符才真正有意义 - 编译器应该已经明白所有其他函数都具有restrict属性(因为从来没有第二个指针指向T)。

Now, if for example you used restrict on operator= you should consequentially not check for self-assignment at all, because you're saying that this is not aliased within the scope of that function (and if that's true , no self-assignment can possibly happen). 现在,例如,如果你使用的restrictoperator=你应该必然不会检查自赋值可言,因为你说this是不是该函数的范围内的别名( 如果这是真的 ,没有自我分配可以可能发生)。
Obviously, this is something that you cannot possibly know in advance, and it's something that doesn't make sense either. 显然,这是你事先不可能知道的事情,而且这也是没有意义的事情。

So, what would be a case where one would actually want to give a member function a restrict qualifier and where it makes sense? 那么,实际上想要给成员函数一个限制限定符以及它有意义的情况会是什么情况呢?

Either I am missing something, or your question does not make sense. 我错过了什么,或者你的问题没有意义。 this is not that different from any other argument to a member function, so why are you surprised that GCC allows you to apply restrict to it? this与成员函数的任何其他参数没有什么不同,那么为什么GCC允许您对其应用restrict感到惊讶?

Regarding applying it to an assignment operator, you rightly point out that it would obviate the need for an explicit self-assignment test. 关于将它应用于赋值运算符,您正确地指出它将消除对显式自赋值测试的需要。 Then you say: 然后你说:

Obviously, this is something that you cannot possibly know in advance 显然,这是你事先不可能知道的事情

But this is always true when you use restrict for anything. 但是当你对任何东西使用restrict时,这总是正确的。 For example, somebody might decide to call memcpy with overlapping memory regions; 例如,某人可能决定调用具有重叠内存区域的memcpy ; you "cannot possibly know in advance" that they will not do so. 你“不可能提前知道”他们不会这样做。 But the restrict declaration for the arguments of memcpy means they have committed an error if they do . 但是memcpy参数的restrict声明意味着如果他们这样做,他们就会犯错误 In exactly the same way, if you declare an assignment operator restrict , you have made it an error for someone to self-assign objects of that class. 以完全相同的方式,如果您声明赋值运算符restrict ,则表示某人自行分配该类的对象是错误的。 There is nothing mysterious or contradictory about this at all; 这根本没有什么神秘或矛盾的; it is just part of the semantics of restrict that it imposes certain constraints on the rest of your code. 它只是restrict语义的一部分,它对代码的其余部分施加了某些约束。

I am also not sure why you find it so impossible for a member function to take a pointer (or reference) to another object of the same type. 我也不确定为什么你发现成员函数不可能将指针(或引用)带到同一类型的另一个对象上。 Trivial example: 琐碎的例子:

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

This sort of thing crops up all the time. 这种事情一直在增加。

So the real question is, why do you think this is so different from any other argument? 所以真正的问题是,为什么你认为this与其他论点有如此不同? Or if you prefer, how did I miss your point so completely? 或者如果你愿意,我怎么完全错过了你的观点?

I belive what you guys are missing is that an argument to a member function could also alias parts or an object. 我相信你们缺少的是成员函数的参数也可以是部分或对象的别名。 Here's an example 这是一个例子

struct some_class {
    int some_value;

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

One would probably expect that to compile to 人们可能希望编译到

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

That code, unfortunately, would be wrong if someone passes a reference to some_value for result. 遗憾的是,如果有人将some_value的引用传递给结果,那么该代码将是错误的 Thus, a compiler would actually need to generate to following 因此,编译器实际上需要生成以下内容

*(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. 请注意,除非compute_something是内联的,否则编译器无法知道结果是否可能是some_value的别名,因此它必须假设最坏的情况,无论是聪明还是愚蠢。 So there a definite and very real advantage to restrict, even if applied to the this pointer. 因此,即使应用于this指针,限制也有明确且非常明显的优势。

The link you posted is interesting. 您发布的链接很有趣。 There will not be a solid use case for having restrict applied on this . 没有坚实的用例来restrict应用this restrict As you mentioned in your question, copy constructor, operator = could have been potential candidates; 正如您在问题中提到的, 复制构造函数,operator =可能是潜在的候选者; but compiler can take care of them. 但编译器可以处理它们。

But following case can be interesting 但以下案例可能很有趣

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

Now use case can be; 现在用例可以;

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;

Though this is very unusual practice, this is the only case I could think of this use case. 虽然这是非常不寻常的做法,但这是我能想到的唯一一个用例。

I'm afraid that I don't clearly understand why you're talking about this . 我担心我不明白为什么你在谈论this

restrict specifies that a pointer is not overlapped with others. restrict指定指针不与其他指针重叠。 So, compilers can assume the memory regions pointed by restrict pointers are not dependent, which allows more aggressive optimizations. 因此,编译器可以假设限制指针指向的内存区域不依赖,这允许更积极的优化。 __restrict__ would be much more effective when used for other pointer variables than this . __restrict__用于比其他指针变量的时候会更加有效this

So, what would be a case where one would actually want to give a member a restrict qualifier and where it makes sense? 那么,如果一个人真的想给一个成员一个限制限定符并且它有意义呢?

Just recall a representative case of using restrict pointers in memcpy : 回想一下在memcpy中使用restrict指针的代表性案例:

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

Adding this as an answer, because it's probably better suited as such (it's kind of an answer and doesn't really belong to the question, plus it's a bit long for a comment). 添加这个作为答案,因为它可能更适合这样(它是一种答案,并不真正属于问题,加上评论有点长)。

After thinking about Nemo's answer for a long time, I believe that our both interpretation about self-assignment is maybe somewhat wrong (though Nemo's was more correct than mine). 在考虑了Nemo的答案很长一段时间之后,我相信我们对自我任命的两种解释可能都有些错误(尽管Nemo比我的更正确)。 As Nemo correctly pointed out, having a restrict-qualified this actually means that presence of aliasing is a program error. 正如Nemo正确指出的那样,具有限制限定this实际上意味着存在别名是一个程序错误。 No more, no less. 不多也不少。

Insofar, when writing this, your logic should actually not be "since you say this cannot happen, you consequentially should not check for self-assignment", but rather "since you explicitly say that aliasing cannot happen, and it's a program error if it does, you not only need to check for self-assignment, but you consequentially must fail hard if it happens". 在写这篇文章的时候,你的逻辑实际上应该不是“因为你说这不会发生,你因此不应该检查自我分配”,而是“因为你明确地说别名不能发生,而且如果它是一个程序错误你不仅需要检查自我分配,而且如果发生这种情况,你必须努力工作。“

And, insofar, it emphasizes a particular program logic and at the same time allows the compiler to optimize better for that particular special case, and thus does indeed make sense . 而且,就此而言,它强调特定的程序逻辑,同时允许编译器针对特定的特殊情况进行更好的优化,因此确实有意义

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM