std::type_index在DLL之间是否安全

Is std::type_index safe across DLLs

本文关键字:之间 是否 安全 DLL index type std      更新时间:2023-10-16

假设我有一个主DLL,其中有一个类如下:

class Test
{
public:
    typedef std::unordered_map< std::type_index, int > Map;
    template < typename T > void SetValue(int val)
    {
        SetValue(std::type_index(typeid(T)), val);
    }
    template < typename T > int GetValue()
    {
        return GetValue(std::type_index(typeid(T)));
    }
protected:
    // Defined in .cpp file
    void SetValue(const std::type_index & idx, int val)
    {
        m_Map[idx] = val;
    }
    // Defined in .cpp file
    int GetValue(const std::type_index & idx)
    {
        Map::const_iterator itr = m_Map.find(idx);
        if (itr != m_Map.cend())
        {
            return itr->second;
        }
        return 0;
    }
private:
    Map m_Map;
};

我通过几个DLL共享该类的一个实例。在其中一个DLL中,我设置了一些值,如下所示:

template < typename T > struct Dummy
{
};
void InitFunc(Test * t)
{
    t->SetValue< Dummy<int> >(32);
    t->SetValue< Dummy<char> >(10);
    t->SetValue< Dummy<float> >(27);
}

在另一个DLL中,我尝试使用相同的Dummy类型来获取这些值。我会得到相同的值还是0?

这在很大程度上取决于您对"安全"的定义和部署环境。

@SergeyA答案的关键是编译器在每个编译单元中生成std::type_info对象,然后在链接每个DLL时由链接器合并这些对象。

虽然std::type_info将具有标准定义的接口,但实现(尤其是存储布局)是一个实现细节,可能会在编译器、编译器版本和编译器选项之间发生变化。

来自CppReference

type_index类是一个围绕std::type_info对象的包装类,该对象可以用作关联容器和无序关联容器中的索引。与type_info对象的关系通过指针""来维护

因此,现在,我们也依赖于每个DLL中指针的几个定义。

想想你可能用std::type_index做的一些事情——结果很可能取决于上下文——很大程度上取决于它们的调用来源。

现在来问一个问题:这安全吗?可能不会。一般来说,应该避免在DLL接口边界上暴露几乎所有的std库(尤其是STL容器)。

如果你坚持这样做,它只会在这些非常有限的情况下改变工作:

  • 所有组件都使用完全相同的编译器构建
  • 所有组件都使用完全相同的编译器选项构建(调试与发布在Windows上一直是一个巨大的问题)
  • 所有组件作为一个单元部署在一起
  • 没有任何组件向任何其他人公开API

事实上,很多商业软件都是这样,你会发现它比你想象的要频繁,但我不推荐它。

如果我正确理解了这个问题,那么你就违反了ODR-One定义规则。看起来你的"Dummy"类型是在两个不同的翻译单位中独立定义的,这是一个no no:)。现在,这将你带入一片未定义的土地,在这里,任何事情都是可能的——你可以得到相同的值,不同的值,或者根本没有值。