2011-06-12 80 views
20

只是想知道是否有人会为我确认一些别名规则。C++别名规则

我知道,混叠(即加载存储问题)可能导致以下类型的代码是次优的,因为我们不能假设x, y, z不重叠:

// 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__,但它们都做同样的事情。

+0

对于容器的例子,除非'&x ==&y'我不相信它们有任何可以重叠的方式,假设符合标准的矢量实现。 – Sven 2011-06-12 07:52:05

+0

@Sven:不同的std :: vector不重叠,但是通常你可以通过引用传递任何对象类型,可能是重叠的。所以我希望编译器需要确保正确性,并保守假设有别名。这就是为什么__restrict进来... – 2011-06-12 07:59:13

+0

@Darran:实际上编译器会做矢量优化或什么时候传递一个对象重载operator [],而不是一个实际的数组或指针?不知何故,我怀疑它。 – Sven 2011-06-12 08:09:03

回答

8

根据strict-aliasing rule,您不允许使用指向不同类型的指针(除char*和朋友之外)指定相同的内存,因此情况4只适用于其中一种类型为char*的情况。

虽然标准没有要求这样做,并且实现可以随意提供其他内容,但情况3与情况1并不完全不同,因为引用是作为所有编译器上的指针实现的。

+0

我同意案例1和3与别名基本相同,但如果您按照案例3使用引用,则不能使用__restrict,这就是为什么我认为通过限制指针传递容器可能会比引用更好... – 2011-06-12 08:04:34

+0

@达伦:C++标准甚至没有提及'__restrict'关键字,它是一个MSVC扩展。也许你应该在这个问题上加上这一点。 – Xeo 2011-06-12 08:24:43

+0

感谢您提供严格的别名信息,这对我来说是新的。情况4可能是实际代码中最常出现的情况,所以别名问题可能不会像我认为的那样频繁发生。和__restrict或restrict,_restrict_等(正如我指出的)是一个C(99)关键字,但GCC和MSVC至少支持C++ – 2011-06-12 08:27:30

4

这对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->datay->dataz->data都是double*,并允许别名。这与使用限制时的情况1,,甚至完全相同。

如果有一个在C restrict关键字++(或使用分机时),最好的办法可能会做plus(vecA.size(), &vecA[0], &vecB[0], &vecB[0]),使用相同的plus作为案例2.而事实上,它可能现在这样做的权利,使用没有restrict的C89风格界面,但使用了封面下的关键字。

+1

你能定义类似struct vector {double * restrict data; //等等};在这种情况下,为了防止混叠? – 2011-06-12 09:30:57

+0

@Darren你可以和它在这种情况下工作,但我认为给定'void f(struct vector * x,struct vector * y)'然后'f(p,p)'是有问题的:'x-> data'将会是'double * restrict',但会替换'y-> data'(IIUC)。 “限制”似乎更像是一种保存特殊情况的有力工具,而不是万能药。 – 2011-06-12 09:35:28