【问题标题】:Is std::type_index safe across DLLsstd::type_index 跨 DLL 是否安全
【发布时间】:2015-12-02 18:35:36
【问题描述】:

假设我有一个主 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?

【问题讨论】:

  • 当您尝试使用在一个 DLL 中创建并传递给另一个 DLL 的 Test ojbect 之一时,您应该更加关注是否会崩溃。您所有的 DLL 都必须使用相同的编译器、相同的选项进行编译,确保使用的堆相同(对于 unordered_map)等等。
  • std::unordered_map 的使用只是一个例子。看来我提出的问题有点错误。我的问题是std::type_index 是否会指向同一个索引。 hash_code 值将是相同的。
  • 我的意思是,除非 DLL 的构建完全相同,否则您甚至不能考虑任何事情。此外,它不一定是unordered_map - 如果您的Test 类最终执行任何 显式或隐式内存管理,那么在DLL 之间使用Test 是有问题的,如果相同的话未使用堆。
  • 我明白了。我猜这回答了我的问题。

标签: c++ c++11 dll


【解决方案1】:

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

@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

这实际上适用于大量商业软件,您会发现这样做的频率比您想象的要多,但我不建议您这样做。

【讨论】:

    【解决方案2】:

    如果我正确理解了这个问题,那么您就违反了 ODR - 单一定义规则。似乎您的“虚拟”类型是在两个不同的翻译单元中独立定义的,这是不可以的:)。现在,这会将您带入未定义的领域,在这里一切皆有可能——您可以获得相同的值、不同的值或根本没有值。

    【讨论】:

    • 这个答案是绝对错误的。 ODR 适用于类模板,而 Dummy 是。见en.cppreference.com/w/cpp/language/definitionThere can be more than one definition in a program, as long as each definition appears in a different translation unit, of each of the following: class type, enumeration type, inline function with external linkage inline variable with external linkage (since C++17), class template, non-static function template, static data member of a class template, member function of a class template, partial template specialization, [...]
    • @Jean-MichaëlCelerier 你跳过了一个重要的部分:..., as long as all of the following is true: ... each definition consists of the same sequence of tokens (typically, appears in the same header file)
    猜你喜欢
    • 2014-01-05
    • 2016-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-26
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    相关资源
    最近更新 更多