【问题标题】:Static member initialization link error静态成员初始化链接错误
【发布时间】:2012-11-28 13:39:16
【问题描述】:

对于即将到来的课程,我试图避免使用虚拟,看看我是否可以挤出更多的性能/内存效率。当我想实现一个 StateManager(课程原型是一个小游戏)时,问题就开始了。

为了实现这一点,我有一个模板来“统计”当前状态的成员函数调用。

一个示例状态是这样的:

struct TestState {
    bool update(float delta) {
        return true;
    }
};

现在状态管理器应该能够接受任何状态类并绑定更新函数。 使用 boost::bind 和 boost::function 很容易实现这一点,但与 virtual 相比性能有所下降,所以我想看看是否可以不使用 boost。

理论上,如果 State 是一个只包含静态函数的类/结构,那会很容易,但这也增加了灵活性,甚至增加了静态初始化的混乱。

StateManager 当前版本是这样的:

 class StateManager
 {
 public:
     template <typename S> static void set(S* state)
     {
         #define UPDATE_ID 0

         StateFunctionHandler<UPDATE_ID, S, bool, float>::bind(std::mem_fun1(&S::update), state);
         m_funcUpdate = StateFunctionHandler<UPDATE_ID, S, bool, float>::exec;
     }
     static bool update(float delta) 
     {
         return m_funcUpdate(delta);
     }
     typedef bool (*funcUpdate)(float);
 private:   
     static funcUpdate m_funcUpdate;
 };

StateFunctionHandler 是负责将成员函数包装在 StateFunctionHandler 的静态成员中的模板。模板的第一个参数是一个 ID,用于为具有相同返回类型和参数的函数强制使用多个模板。

在代码中是这样的:

template <int ID, typename S, typename R, typename A>
struct StateFunctionHandler 
{ 
    static void bind(std::mem_fun1_t<R, S, A> f, S* s)
    {
        func = f;
        pState = s;
    } 
    static R exec(A arg) 
    { 
        return func(pState, arg); 
    } 

    static std::mem_fun1_t<R, S, A> func; 
    static S* pState; 
};

现在的问题是为用例初始化 StateFunctionHandler 的模板化静态成员,因为我们需要强制编译器初始化它们。

在与这些类​​关联的 cpp 文件中,静态成员被初始化:

template <int ID, typename S, typename R, typename A> std::mem_fun1_t<R, S, A> StateFunctionHandler<ID, S, R, A>::func;
template <int ID, typename S, typename R, typename A> S* StateFunctionHandler<ID, S, R, A>::pState = NULL;

StateManager::funcUpdate StateManager::m_funcUpdate = NULL;

但我收到 StateFunctionHandler::func 和 ::pState 的链接错误 (LNK2001),因此编译器似乎没有初始化 StateFunctionHandler 的静态成员。

用例:

 TestState* t = new TestState();
 StateManager::set(t);
 StateManager::update(0.1f);

再次声明,我不想使用boost,这是一个实验,看看我是否可以在这个用例中避免使用虚函数并具有性能。

【问题讨论】:

  • 链接错误通常意味着您没有将所有对象链接在一起,初始化顺序很重要——但这会导致运行时错误。
  • 我知道这是一个实验,但是您是否分析过您的代码以查看性能影响是什么?优化的问题在于它经常损害代码质量,而且通常只在一小部分代码中是必要的。你所做的似乎真的过分了。记住这句话:“过早的优化是万恶之源”。
  • 链接错误与绑定函数中的赋值有关,因为在调用绑定时 pState/func 似乎不存在。如果无法编译代码,我无法比较性能。尝试使用它的主要原因是编译器可以更好地优化非虚拟函数。因为这是一个实验,我不介意做坏事:)
  • "我试图避免使用虚拟,看看我是否可以挤出更多的性能/内存效率。"前提失败。
  • 虚拟可能会很慢,但看起来您只是在明确地重新发明它们,所以不要期望性能会提高。状态上的虚拟update 函数无论如何都不会出现在分析中。只有当你在紧密的内部循环上调用 virtuals 时,你才需要担心这个。

标签: c++ templates static


【解决方案1】:

您应该将静态模板类成员的初始化移动到头文件中。

它应该在每个实例化模板的翻译单元中可见,与非静态模板类成员一样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 2015-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多