简体   繁体   English

C++ 别名规则

[英]C++ aliasing rules

Just wondering if someone would confirm a few aliasing rules for me.只是想知道是否有人会为我确认一些别名规则。

I know that aliasing (ie load-store issues) could cause the following type of code to be suboptimal, because we can't assume that x, y, z don't overlap:我知道别名(即加载存储问题)可能会导致以下类型的代码不是最理想的,因为我们不能假设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];
} 

I know that there's a C keyword __restrict that hints to the compiler that it shouldn't consider the overlapping case, and hence potentially generate better code:我知道有一个 C 关键字__restrict向编译器暗示它不应该考虑重叠的情况,因此可能会生成更好的代码:

// case 2:
void plus(size_t n, double *__restrict x, double *__restrict y, double *__restrict z)
{ // as above... }

But how does aliasing work with C++ style code, where we would be dealing with container objects passed by reference, rather than the C-like examples above with raw pointers??但是别名如何与 C++ 样式代码一起使用,我们将在其中处理通过引用传递的容器对象,而不是上面使用原始指针的类 C 示例?

For instance, I'm assuming that there would be aliasing issues if we did the following:例如,我假设如果我们执行以下操作会出现别名问题:

// case 3:
void plus(std::vector<double> &x, std::vector<double> &y, std::vector<double> &z)
{ // similar to above... }

And to move to a less trivial example, does it make any difference if the underlying data types in the containers are different??再举一个不那么琐碎的例子,如果容器中的底层数据类型不同,会有什么不同吗? At the implementation level most containers dynamically manage storage with pointers, so it's not clear to me how the compiler could ensure that the following doesn't alias:在实现级别,大多数容器使用指针动态管理存储,因此我不清楚编译器如何确保以下内容没有别名:

// case 4:
void foo(std::vector<mytype1> &x, std::vector<mytype2> &y)
{ // interwoven operations on x, y... }

I'm not trying to micro-optimise, but I'm wondering if it's currently better to pass restricted pointers to containers around, rather than references.我不是在尝试进行微优化,但我想知道目前是否最好将受限指针传递给周围的容器,而不是引用。

EDIT: To clear up some terminology, as pointed out: restrict is the C99 keyword.编辑:清除一些术语,正如所指出的: restrict是 C99 关键字。 There's also __restrict and __restrict__ in various compilers, but they all do the same thing.各种编译器中也有__restrict__restrict__ ,但它们都做同样的事情。

According to thestrict-aliasing rule , you are not allowed to alias the same memory with pointers to different types (except char* and friends), so case 4 could only apply if one of the types was a char* .根据严格别名规则,您不能使用指向不同类型( char*和朋友除外)的指针对相同的 memory 进行别名,因此只有当其中一种类型是char*时,案例 4 才适用。

Case 3 though isn't all that different from case 1, as references are implemented as pointers on all compilers I know, though the standard doesn't demand that and an implementation is free to come up with something else.案例 3 与案例 1 并没有太大的不同,因为引用在我知道的所有编译器上都是作为指针实现的,尽管标准不要求这样做,并且实现可以自由地提出其他东西。

It's not specific at all to C++.它根本不特定于 C++。 Consider this C99 bit:考虑这个 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
}

Here, restrict buys us very little: x->data , y->data and z->data are all double* and are allowed to alias.在这里, restrict对我们的影响很小: x->datay->dataz->data都是double*并且允许使用别名。 This is exactly like case 1, even when using restrict.这与案例 1 完全相同,即使在使用限制时也是如此。

If there were a restrict keyword in C++ (or when using an extension), the best bet would probably to do plus(vecA.size(), &vecA[0], &vecB[0], &vecB[0]) , using the same plus as in case 2. And in fact it's possible to do this right now, using a C89-style interface without restrict but that uses the keyword under the covers.如果 C++ 中有一个restrict关键字(或使用扩展名时),最好的办法可能是plus(vecA.size(), &vecA[0], &vecB[0], &vecB[0]) ,使用相同的plus上案例 2。事实上,现在可以使用 C89 风格的界面来执行此操作,而无需restrict ,但在幕后使用关键字。

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

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