成员变量(属性)可以驻留在 C++ 中的寄存器中吗?
Can a member variable (attribute) reside in a register in C++?
局部变量(比如 int)可以存储在处理器寄存器中,至少只要它的地址在任何地方都不需要。考虑一个计算某些东西的函数,比如一个复杂的散列:
int foo(int const* buffer, int size)
{
int a; // local variable
// perform heavy computations involving frequent reads and writes to a
return a;
}
现在假设缓冲区不适合内存。我们写了一个 class 用于从数据块中计算散列,多次调用 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
是自由函数中的局部变量,现在是对象的成员变量,因此状态在多次调用中得以保留。
现在的问题是:编译器在 foo
方法的开头将 a
加载到寄存器中并在末尾将其存储回是否合法?实际上,这意味着监视对象的第二个线程永远无法观察到 a
的中间值(除了同步和未定义的行为)。如果速度是 C++ 的主要设计目标,这似乎是合理的行为。标准中是否有任何内容可以阻止编译器执行此操作?如果不是,编译器真的会这样做吗?换句话说,除了在函数的开始和结束时加载和存储一次成员变量之外,我们是否可以预期使用成员变量会带来(可能很小的)性能损失?
据我所知,C++语言本身连寄存器是什么都没有规定。但是,我认为这个问题无论如何都很清楚。无论这是否重要,我都感谢标准 x86 或 x64 架构的答案。
对"Can a member variable (attribute) reside in a register?"的简短回答:是的。
当遍历缓冲区并将临时结果写入任何类型的原语时,无论它位于何处,将临时结果保存在寄存器中将是一个很好的优化。这在编译器中经常完成。但是,它是基于实现的,甚至会受到传递标志的影响,因此要了解结果,您应该检查生成的程序集。
如果(且仅当)编译器可以证明在 foo
的执行期间没有其他任何东西可以访问 a
。
一般来说,这是一个非常重要的问题;我认为没有任何编译器试图解决它。
考虑(更人为的)例子
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);
"Optimising" 这会在 baz.a
中留下 12
,而不是 23
,这显然是错误的。
局部变量(比如 int)可以存储在处理器寄存器中,至少只要它的地址在任何地方都不需要。考虑一个计算某些东西的函数,比如一个复杂的散列:
int foo(int const* buffer, int size)
{
int a; // local variable
// perform heavy computations involving frequent reads and writes to a
return a;
}
现在假设缓冲区不适合内存。我们写了一个 class 用于从数据块中计算散列,多次调用 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
是自由函数中的局部变量,现在是对象的成员变量,因此状态在多次调用中得以保留。
现在的问题是:编译器在 foo
方法的开头将 a
加载到寄存器中并在末尾将其存储回是否合法?实际上,这意味着监视对象的第二个线程永远无法观察到 a
的中间值(除了同步和未定义的行为)。如果速度是 C++ 的主要设计目标,这似乎是合理的行为。标准中是否有任何内容可以阻止编译器执行此操作?如果不是,编译器真的会这样做吗?换句话说,除了在函数的开始和结束时加载和存储一次成员变量之外,我们是否可以预期使用成员变量会带来(可能很小的)性能损失?
据我所知,C++语言本身连寄存器是什么都没有规定。但是,我认为这个问题无论如何都很清楚。无论这是否重要,我都感谢标准 x86 或 x64 架构的答案。
对"Can a member variable (attribute) reside in a register?"的简短回答:是的。
当遍历缓冲区并将临时结果写入任何类型的原语时,无论它位于何处,将临时结果保存在寄存器中将是一个很好的优化。这在编译器中经常完成。但是,它是基于实现的,甚至会受到传递标志的影响,因此要了解结果,您应该检查生成的程序集。
如果(且仅当)编译器可以证明在 foo
的执行期间没有其他任何东西可以访问 a
。
一般来说,这是一个非常重要的问题;我认为没有任何编译器试图解决它。
考虑(更人为的)例子
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);
"Optimising" 这会在 baz.a
中留下 12
,而不是 23
,这显然是错误的。