【问题标题】:Initializing static global data using function call (at compile time)使用函数调用初始化静态全局数据(在编译时)
【发布时间】:2012-08-28 21:14:30
【问题描述】:

我试图通过在编译时计算数字序列并将它们存储为静态向量来节省计算时间(但我现在可能会在运行时开始计算一次)。我正在尝试做的一个简单(非编译)示例是:

#include <vector>
using namespace std;

static vector<vector<int> > STATIC_THING(4, vector<int>(4));

void Generator(int x, int y, vector<int> *output) {
  // Heavy computing goes here
  for(int i=0; i < 4; ++i)
    (*output)[i] = x * y;
  return;
}   
static void FillThings() {
  for(int x=0; x < 4; ++x)
    for(int y=0; y < 4; ++y)
      Generator(x, y, &STATIC_THING[x]);
}   
FillThings();

int main() {
}   

除了将我的序列预计算和硬编码到数组中之外,还有其他方法可以让编译器解决这个问题吗?我觉得应该有一种方法至少可以在头文件的第一个#include 上完成这项工作,但我只看到它与类一起完成。如果它有助于在编译时进行计算,我可以使用数组而不是向量。

编辑:

  • 虽然有人建议使用模板元编程,但我的实际生成器算法过于复杂,不适合这种技术。

  • 使用查找表似乎是我唯一可以避免运行时计算的其他选择;如果将来性能仍然是一个问题,我会依靠这个。

【问题讨论】:

  • 为什么不直接使用构造函数呢?而不是STATIC_THINK,使用一个包含向量的对象。如果需要,您可以将其设为单例。
  • 我已经在传递中完成了该操作,在构造函数中创建了具有数据成员和初始化程序的类,其中我创建了一个静态实例。我可以走那条路,但我更感兴趣的是弄清楚为什么我不能像上面那样完成这项工作,如果没有其他原因,就是为了学习新东西。

标签: c++ performance static


【解决方案1】:

这样做:

static int FillThings() {
  for(int x=0; x < 4; ++x)
    for(int y=0; y < 4; ++y)
     Generator(x, y, &STATIC_THING[x]);
  return 9087;
}   
static int q = FillThings();

【讨论】:

  • 我喜欢这个解决方案,很清楚。为什么我不能只调用该函数,为什么编译器在以这种方式调用时不抱怨? @Kerrek,我以前没见过这个符号,它的主要用途是什么?
  • 这给了我未使用的变量警告,有没有好的方法来抑制这些?
  • 您可以删除static。您也可以在某处以无害的方式使用q。在FillThings 中添加q=0; 可能会做到这一点。
【解决方案2】:

如果您无法通过大括号初始化程序从实际文字进行初始化,那么您可以执行以下操作:

typename std::vector<std::vector<int>> my_vector;

static my_vector make_static_data()
{
    my_vector result;
    // ... populate ...
    return result;
}

static const my_vector static_data = make_static_data();

【讨论】:

  • 唯一的问题是在我的真实代码中会有一个非常大的对象返回值。
  • @ethereal:为什么会有这样的问题?几乎可以肯定会有 RVO,而且无论如何是在程序启动期间。
  • 要点回复:RVO,但我关心的一个问题是完整的程序执行时间。当我可以以最小的努力确保优化时,我宁愿不把优化留给编译器!
  • 要成为魔鬼的拥护者,我想说如果性能是您关心的问题,您应该将其留给编译器,这可能比您包含更多的编译经验 :-)
【解决方案3】:

没那么容易:std::vector 是一个动态结构。它不是“可填充的”和“编译时间”。它可以在启动时通过使用调用函数或 lambda 的返回来初始化静态变量来填充,该函数实际上填充了向量。

this可以是一种方式。

但是一个合适的“编译时向量”应该看起来像一个模板,它的“索引”是一个作为参数给出的 int,比如

template<unsigned idx>
struct THING
{
    static const int value = .... //put a costant expression here
};

用作THING&lt;n&gt;::value

“常量表达式”可以是 function(THING&lt;idx-1&gt;::value),递归到专门的

temnplate<>
struct THING<0U> {};

这会停止编译器递归。

但是,有一些限制:定义 value 静态成员的表达式必须是 constexpr(因此,只有整数类型,内置操作,没有 &lt;cmath&gt;,只有用 constexpr 声明的函数),并且用作idx 的值本身必须是常量(而不是变量)。

【讨论】:

  • 这看起来比它的价值更复杂。有没有办法在编译时使用数组而不是向量进行计算?
  • 经过一番挖掘,我认为您的建议称为“模板元编程”。我的代码有点过于冗长和复杂,不适合这种技术。
  • 简短回答:否。长答案:在编译时没有变量,只有整数常量和类型。您可以相互依赖地生成它们,但不能在编译时分配给变量。初始化是一个运行时活动。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多