只是想知道是否有人会为我确认一些别名规则。
我知道别名(即加载存储问题)可能导致以下类型的代码不是最佳的,因为我们不能假设 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__
,但它们都做同样的事情。
最佳答案
根据strict-aliasing rule ,您不能使用指向不同类型的指针(除了 char*
和 friend )给同一内存起别名,因此情况 4 仅适用于其中一种类型是 char*
.
案例 3 与案例 1 并没有什么不同,因为在我知道的所有编译器上,引用都是作为指针实现的,尽管标准不要求这样做,并且可以自由地提出其他实现。
关于C++ 别名规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6320789/