笔记: 要澄清,问题不是关于使用 restrict 一般而言,关键字,但特别是将其应用于成员函数如所述 这里.

GCC允许您使用 __restrict__ (GNU ++等于C99 restrict)成员功能的预选赛,有效地制作 this 限制了函数范围内的合格指针。牛肉在哪里?

大多数成员功能都适用于其他成员,通过 this, ,这是一个 T* const (并且通常没有偏见)。为了 this 要使可能的混蛋,需要以某种方式在成员函数中使用第二个指针到类型,并且必须来自某个地方。
这种情况通常是非成员功能的情况,例如所有二进制操作员或任何其他免费的函数,这些功能至少采用两个相同的非平凡类型的指针或参考。但是,这些功能没有 this, ,所以它们无关紧要。

作业操作员,复制构造函数和一般比较操作员是成员函数的示例 this 可以 原则上是混叠的(因为另一个对象是通过参考传递的)。因此,为这些分配限制符确实很有意义 - 编译器应该已经显而易见的是所有其他功能都具有限制性属性(因为从来没有第二个指针到T)。

现在,例如,您使用了 restrictoperator= 你应该 因此 根本不检查自我分配,因为您是说 this 在该功能的范围内不被别名(和 如果那是真的, ,不可能发生自我分配)。
显然,这是您不可能提前知道的事情,这也没有意义。

那么,在某种情况下,人们实际上想为成员函数提供限制性资格和有意义的情况吗?

有帮助吗?

解决方案

我要么缺少某些东西,要么您的问题没有意义。 this 不是 与任何其他参数与成员函数不同,所以为什么您会惊讶地发现GCC允许您应用 restrict 它?

关于将其应用于作业操作员,您正确地指出,它将消除需要进行显式自我分配测试的需求。然后你说:

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

但这是 总是 当您使用时是真的 restrict 为了任何东西。例如,有人可能决定打电话 memcpy 与重叠的内存区域;您“不可能提前知道”他们不会这样做。但是 restrict 关于论点的声明 memcpy 方法 如果他们这样做,他们犯了一个错误. 。以完全相同的方式,如果您声明了作业操作员 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

不幸的是,该代码将是 错误的 如果某人向某些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是inline,否则编译器具有 知道结果是否可以别名some_value的方式,所以 假设最糟糕的情况,无论它没有什么聪明或愚蠢的情况。因此,即使应用于该指针,也有明确且非常真正的优势。

您发布的链接很有趣。没有可靠的用例 restrict 应用于 this. 。正如您在问题中提到的那样, 复制构造函数,操作员= 可能是潜在的候选人;但是编译器可以照顾他们。

但是以下情况可能很有趣

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.

那么,在某种情况下,人们实际上想给成员一个限制性限制者且有意义的情况是什么?

只是回忆起使用的代表案例 restrict 指针 memcpy:

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

将其添加为答案,因为它可能更适合这样(这是一个答案,并不属于这个问题,而且要发表评论有点久)。

在考虑了长期以来的Nemo回答之后,我相信我们对自我分配的两种解释也许有些不对劲(尽管Nemo的解释比我的更正确)。正如Nemo正确指出的那样,具有限制性的资格 this 实际上意味着存在混叠是程序错误。不再,也没有。

就在写这篇文章时,您的逻辑实际上不应该是“因为您说这不可能发生,因此您不应检查自我分配”,而是“因为您明确地说出来的混音不可能发生,并且如果它是程序错误,则是一个错误做,你 不仅 需要检查自我分配,但是您需要 必须 如果发生的话,难以失败”。

而且,就特定而言,它强调了特定的程序逻辑,同时允许编译器为该特定情况更好地优化,从而优化 确实有意义.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top