在C++中,我可以声明一个引用,以表明没有任何东西可以修改它吗?

Owe*_*wen 16 c++ optimization reference c++11

如果我做

typedef void Cb();

int foo(int const& a, Cb cb) {
  int x = a;
  cb();
  return x - a;
}
Run Code Online (Sandbox Code Playgroud)

并编译g++ -O3 -save-temps -c foo.cpp,我看到减法被保留,而如果cb();被注释掉,整个函数优化为

xorl    %eax, %eax
Run Code Online (Sandbox Code Playgroud)

我可以对参数的规范做些什么,a这样无论调用是什么,都可以优化减法cb(),并且不会强制a成为唯一的引用(即,它可能被引用到其他地方,但是没有那些引用会被修改)?

M.M*_*M.M 15

执行建议的优化是不正确的,因为其余代码可能是:

static int var;

void func()
{
    var++;
}

// ...
foo(var, func);
Run Code Online (Sandbox Code Playgroud)

我不知道你可以设置任何特定于编译器的属性来表示cb()不会修改a.

  • 解决方法是按值取a`,或在调用`cb`之前计算返回值 (3认同)

pep*_*ico 15

__restrict扩展名,你可以在gcc.godbolt.org上试试这个:

typedef void Cb();

int foo(const int & __restrict a, Cb cb) {
  int x = a;
  cb();
  return x - a;
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,只有clang进行优化,gcc不会这样做.


请注意,类似限制的别名被认为是C++标准的一部分:

也许将来你可以通过标准来做到这一点.


mid*_*dor 6

你为什么不在int x = a;函数调用下面移动这一行?

如果cb()既不影响x也不a应该这样做,我认为编译器会再次优化调用,因为x不能在两次调用之间改变.如果您无法重新排序这两个调用,则可能无法首先对其进行优化.

这不是你可以暗示编译器要做的事情,因为在调用之后无法保证x和a都没有改变cb().

将此视为读/写访问的顺序.如果没有读取或写入访问ax过程中会发生cb(),你可以做函数调用的手动重新排序.

如果ax写入,则无法重新排序,并且优化不正确.

如果x被读取,则不能对函数调用进行重新排序,但如果x真正只读取,则可以从a读取,并且x仅在调用之后定义,因为它具有与a调用之前声明的值相同的值.


Ded*_*tor 5

restrict如果编译器支持该扩展,则可以在引用上使用C.
(某些编译器允许__restrict或者__restrict__,它们是实现命名空间的一部分.)

这是您向编译器的承诺,即对象在任何地方都没有别名,因此可以对其进行优化.
如果你对编译器撒了谎,那么你就得到了你应得的破解代码.