成员变量(属性)可以驻留在C ++中的寄存器中吗?

时间:2016-10-11 13:56:14

标签: c++ attributes member volatile cpu-registers

局部变量(比如int)可以存储在处理器寄存器中,至少只要在任何地方都不需要它的地址。考虑一个计算某事的函数,比如复杂的哈希:

int foo(int const* buffer, int size)
{
    int a;   // local variable
    // perform heavy computations involving frequent reads and writes to a
    return a;
}

现在假设缓冲区不适合内存。我们编写了一个用于从数据块计算哈希值的类,多次调用foo

struct A
{
    void foo(int const* buffer, int size)
    {
        // perform heavy computations involving frequent reads and writes to a
    }

    int a;
};

A object;
while (...more data...)
{
    A.foo(buffer, size);
}
// do something with object.a

这个例子可能有点人为。这里的重要区别是a是自由函数中的局部变量,现在是对象的成员变量,因此状态在多个调用中保留。

现在的问题是:编译器在a方法的开头加载foo到寄存器并将其存储在最后是否合法?实际上,这意味着监视对象的第二个线程永远不会观察到a的中间值(除了同步和未定义的行为)。如果速度是C ++的主要设计目标,那么这似乎是合理的行为。标准中是否有任何东西可以阻止编译器执行此操作?如果不是,编译器实际上是这样做的吗?换句话说,除了在函数的开头和结尾加载和存储一次,我们可以期望使用成员变量的(可能很小的)性能损失吗?

据我所知,C ++语言本身甚至没有指定寄存器是什么。但是,无论如何,我认为这个问题很清楚。无论如何,我都很欣赏标准x86或x64架构的答案。

2 个答案:

答案 0 :(得分:2)

编译器可以执行此操作,如果(并且仅当)它可以证明在a执行期间没有其他任何内容可以访问foo。 这一般是一个非常重要的问题;我不认为任何编译器试图解决它。

考虑(甚至更人为的)例子

struct B
{
    B (int& y) : x(y) {}
    void bar() { x = 23; }
    int& x;
};

struct A
{
    int a;
    void foo(B& b)
    {
        a = 12;
        b.bar();            
    }
};

看起来很无辜,但后来我们说

A baz;
B b(baz.a);
baz.foo(b);

“优化”这会将12留在baz.a,而不是23,这显然是错误的。

答案 1 :(得分:1)

简短回答"成员变量(属性)可以驻留在寄存器中吗?":是。

当迭代缓冲区并将临时结果写入任何类型的原语时,无论它驻留在哪里,将临时结果保存在寄存器中都是一个很好的优化。这在编译器中经常发生。但是,它是基于实现的,甚至受传递标志的影响,因此要知道结果,您应该检查生成的程序集。