在C ++中,我可以声明一个引用,以表明什么都不会修改它?

时间:2014-12-04 16:48:22

标签: c++ c++11 optimization reference

如果我这样做

typedef void Cb();

int foo(int const& a, Cb cb) {
  int x = a;
  cb();
  return x - a;
}

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

xorl    %eax, %eax

我可以对参数a的规范做些什么,这样无论对cb()的调用如何,都不会优化减法,也不会强制a为唯一引用(即,它可以在别处引用,但是那些引用都不会被修改)?

5 个答案:

答案 0 :(得分:15)

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

static int var;

void func()
{
    var++;
}

// ...
foo(var, func);

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

答案 1 :(得分:15)

__restrict扩展程序,您可以在gcc.godbolt.org上尝试此操作:

typedef void Cb();

int foo(const int & __restrict a, Cb cb) {
  int x = a;
  cb();
  return x - a;
}

奇怪的是,only clang does the optimizationgcc doesn't do it


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

也许将来你可以按标准来做。

答案 2 :(得分:6)

为什么不在功能调用下移动int x = a;行?

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

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

将此视为读/写访问顺序。如果在a期间未对xcb()发生读写访问,您可以手动重新排序函数调用。

如果写入ax,则无法重新排序,优化也不正确。

如果读取了x,则无法对函数调用进行重新排序,但如果只读取x,则可以从中读取,并且仅在调用后定义x如果您在通话前声明它,它将具有与a相同的值。

答案 3 :(得分:5)

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

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

答案 4 :(得分:-1)

__ attribute __((const))就够了

如下所述:https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Function-Attributes.html,它告诉编译器给定的函数不会修改全局变量(尽管它可以读取它们)。

还有pure的{​​{1}}子集,它也禁止全局读取。

考虑以下简化示例:

const

int __attribute__((const)) g(); int f(int a) { int x = a; g(); return x - a; } 4.8 x86_64 g++上,汇编为:

  • -O3xor %eax,%eax
  • 不假设const的大型函数在没有a
  • 的情况下不会被修改

似乎没有更细粒度的属性表示函数不会根据需要修改给定的变量。

可以将__attribute __((const))应用于函数指针吗?

试试吧:

const

再一次,它编译为int f(int& a, void __attribute__((const)) (*g)(void)) { int x = a; (*g)(); return x - a; } ,并编译为没有xor %eax,%eax的大型函数,所以答案是肯定的。

Function pointer to __attribute__((const)) function?

中询问了此语法

它也出现在2011年的邮件列表上:http://comments.gmane.org/gmane.comp.gcc.help/38052至少在当时,它只适用于某些属性。

可以将__attribute __((const))添加到typedef吗?

这有效:

const

或:

typedef void __attribute__((const)) (*g_t)(void);

int f(int& a, g_t g) {
    int x = a;
    (*g)();
    return x - a;
}

但我无法找到一种方法将属性放在typedef 传递函数,而不是指针,如:

typedef void (g_t)(void);

int f(int& a, g_t __attribute__((const)) g) {
    int x = a;
    g();
    return x - a;
}

GCC发出警告,说明在这种情况下该属性被忽略了。