限制对成员功能的预选赛(限制此指针)
-
25-10-2019 - |
题
笔记: 要澄清,问题不是关于使用 restrict
一般而言,关键字,但特别是将其应用于成员函数如所述 这里.
GCC允许您使用 __restrict__
(GNU ++等于C99 restrict
)成员功能的预选赛,有效地制作 this
限制了函数范围内的合格指针。牛肉在哪里?
大多数成员功能都适用于其他成员,通过 this
, ,这是一个 T* const
(并且通常没有偏见)。为了 this
要使可能的混蛋,需要以某种方式在成员函数中使用第二个指针到类型,并且必须来自某个地方。
这种情况通常是非成员功能的情况,例如所有二进制操作员或任何其他免费的函数,这些功能至少采用两个相同的非平凡类型的指针或参考。但是,这些功能没有 this
, ,所以它们无关紧要。
作业操作员,复制构造函数和一般比较操作员是成员函数的示例 this
可以 原则上是混叠的(因为另一个对象是通过参考传递的)。因此,为这些分配限制符确实很有意义 - 编译器应该已经显而易见的是所有其他功能都具有限制性属性(因为从来没有第二个指针到T)。
现在,例如,您使用了 restrict
上 operator=
你应该 因此 根本不检查自我分配,因为您是说 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
实际上意味着存在混叠是程序错误。不再,也没有。
就在写这篇文章时,您的逻辑实际上不应该是“因为您说这不可能发生,因此您不应检查自我分配”,而是“因为您明确地说出来的混音不可能发生,并且如果它是程序错误,则是一个错误做,你 不仅 需要检查自我分配,但是您需要 必须 如果发生的话,难以失败”。
而且,就特定而言,它强调了特定的程序逻辑,同时允许编译器为该特定情况更好地优化,从而优化 确实有意义.