【发布时间】:2013-11-21 23:40:50
【问题描述】:
我面临一个有趣的优化问题。
在由大量类组成的大型代码库中,在许多地方,非常经常使用/检查非常量全局(=文件范围)变量的值,并且该变量的不必要的内存访问是为了避免。
这个变量被初始化了一次,但是由于它的初始化比较复杂,需要调用很多函数,所以不能这样初始化,在main()执行之前:
unsigned size = 1000;
int main()
{
// some code
}
或
unsigned size = CalculateSize();
int main()
{
// some code
}
相反,它必须像这样初始化:
unsigned size;
int main()
{
// some code
size = CalculateSize();
// lots of code (statically/dynamically created class objects, whatnot)
// that makes use of "size"
return 0;
}
仅仅因为size 不是常量并且它是全局的(=文件范围)并且代码又大又复杂,编译器无法推断size 在size = CalculateSize(); 之后永远不会改变。编译器生成的代码从变量中获取和重新获取 size 的值,并且不能将其“缓存”在寄存器或可能与 CPU 的 d-cache 一起存在的本地(堆栈上)变量中其他经常访问的局部变量。
所以,如果我有类似以下的内容(出于说明目的而编造的示例):
size = CalculateSize();
if (size > 200) blah1();
blah2();
if (size > 200) blah3();
编译器认为blah1() 和blah2() 可能会改变size 并在if (size > 200) blah3(); 中生成从size 读取的内存。
我希望尽可能避免额外阅读。
显然,像这样的黑客攻击:
const unsigned size = 0;
int main()
{
// some code
*(unsigned*)&size = CalculateSize();
// lots more code
}
不会这样做,因为它们会调用未定义的行为。
问题是如何通知编译器它可以“缓存”size 的值一旦执行了size = CalculateSize(); 并且不调用未定义的行为,未指定的行为,希望实现特定的行为。
C++03 和 g++ (4.x.x) 需要此功能。 C++11 可能是也可能不是一个选项,我不确定,我试图避免使用高级/现代 C++ 功能以保持在编码指南和预定义工具集内。
到目前为止,我只想出了一个技巧,在每个使用它的类中创建 size 的常量副本并使用该副本,就像这样(decltype 使它成为 C++11,但我们可以不用decltype):
#include <iostream>
using namespace std;
volatile unsigned initValue = 255;
unsigned size;
#define CACHE_VAL(name) \
const struct CachedVal ## name \
{ \
CachedVal ## name() { this->val = ::name; } \
decltype(::name) val; \
} _CachedVal ## name;
#define CACHED(name) \
_CachedVal ## name . val
class C
{
public:
C() { cout << CACHED(size) << endl; }
CACHE_VAL(size);
};
int main()
{
size = initValue;
C c;
return 0;
}
以上内容可能只在一定程度上有所帮助。是否有更好、更具启发性的编译器替代方案是合法的 C++?希望有一个侵入性最小(源代码方面)的解决方案。
更新:为了更清楚一点,这是在性能敏感的应用程序中。这并不是说我想摆脱对特定变量的不必要读取。我试图让/使编译器产生更优化的代码。任何涉及像 size 那样频繁地读取/写入另一个变量的解决方案以及像 size 那样经常执行的解决方案中的任何附加代码(尤其是分支和条件分支)也会影响性能。我不想在一个地方赢,却在另一个地方失去同样甚至更多。
这是一个相关的non-solution, causing UB(至少在 C 中)。
【问题讨论】:
-
你试过
const_cast吗?看起来这是一个完美的用例。 -
@ViníciusGobboA.deOliveira 你到底在暗示什么?
-
@AlexeyFrunze 您真的应该尝试使用静态 const 变量方法的返回来分析 - 检查我编辑的答案。
-
只看
const_cast的文档,不能用于这个。它将导致未定义的行为,这意味着它不是一个选项。
标签: c++ optimization constructor constants