问题描述
|
只是想知道是否有人会为我确认一些别名规则。
我知道别名(即负载存储问题)可能会导致以下类型的代码不理想,因为我们不能假设ѭ0不会重叠:
// case 1:
void plus(size_t n,double *x,double *y,double *z)
{
for (size_t i = 0; i != n; ++i)
z[i] = x[i] + y[i];
}
我知道有一个C关键字__restrict
告诉编译器它不应该考虑重叠情况,因此有可能生成更好的代码:
// case 2:
void plus(size_t n,double *__restrict x,double *__restrict y,double *__restrict z)
{ // as above... }
但是别名如何与C ++样式代码一起工作,在这里我们将处理通过引用传递的容器对象,而不是上面带有原始指针的类似C的示例?
例如,我假设如果执行以下操作,将会出现混叠问题:
// case 3:
void plus(std::vector<double> &x,std::vector<double> &y,std::vector<double> &z)
{ // similar to above... }
再举一个不那么琐碎的例子,如果容器中的基础数据类型不同,这有什么区别吗?在实现级别,大多数容器都使用指针动态管理存储,因此我不清楚编译器如何确保以下内容不具有别名:
// case 4:
void foo(std::vector<mytype1> &x,std::vector<mytype2> &y)
{ // interwoven operations on x,y... }
我没有尝试进行微优化,但是我想知道将受限制的指针传递给容器,而不是引用,目前是否更好。
编辑:指出来清除一些术语:restrict
是C99关键字。在各种编译器中也有__restrict
和__restrict__
,但是它们都做相同的事情。
解决方法
根据严格的别名规则,不允许您使用指向不同类型的指针(same9ѭ和朋友除外)对同一内存进行别名别名,因此情况4仅在类型之一为
char*
的情况下适用。
情况3与情况1并没有什么不同,因为在我所知道的所有编译器上,引用都是作为指针实现的,尽管该标准并不要求这样做,并且实现可以自由提出其他建议。
, 它根本不是C ++特有的。考虑一下此C99位:
struct vector {
double* data;
size_t n;
};
void
plus(struct vector* restrict x,struct vector* restrict y,struct vector* restrict z)
{
// same deal as ever
}
在这里,restrict
买给我们的东西很少:x->data
,y->data
和z->data
都是double*
,并且允许使用别名。即使使用限制,这也与情况1完全相同。
如果C ++中有一个restrict
关键字(或使用扩展名),最好的选择可能是使用情况2中相同的ѭ19do来进行ѭ18And。实际上,现在可以使用C89风格的界面,不带ѭ6,但在幕后使用了关键字。