std::type_index在DLL之间是否安全
Is std::type_index safe across DLLs
假设我有一个主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:)。现在,这将你带入一片未定义的土地,在这里,任何事情都是可能的——你可以得到相同的值,不同的值,或者根本没有值。
- std::memmove在同一对象之间是否始终安全
- std::weak_ptr 和相应的 std::shared_ptr 之间是否存在数据竞争?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- C++:这两种将数字写入矩阵的方式之间是否存在显着的速度差异?
- char 和 char& 之间是否存在相对复制开销差异?
- libstdc++的make_shared布局在gcc 4.x和gcc 6.x之间是否发生了变化?
- 如果检查和内联条件之间是否存在编译器差异
- __has_include() 和后续 #include 之间是否存在争用条件
- 这些编译器之间是否有任何区别
- std :: vector用作堆栈和std :: stack之间是否存在任何复杂性差异
- 链接时,"grab what you need" 和 "grab all" 之间是否有某些内容(-wl,--whole-archive)?
- 调用 ADL 时,表达式和命名空间之间是否会发生冲突
- 将全局声明为类声明语句的一部分与使用单独的语句声明全局之间是否有区别
- 返回值 vkEnumeratePhysicalDevices 在不同的 VkInstances 之间是否一致?
- 放置 new 的返回值与其操作数的强制转换值之间是否存在(语义)差异
- vector.size()= 0和vector.empty()之间是否有区别
- 显式运算符 = 调用和 = 运算符之间是否有区别
- IF(INTVAR)和IF(intvar!= 0)之间是否存在区别
- 结构数据D = {0}和结构数据D = {}之间是否存在任何区别
- 编译时,复制构造函数/复制分配和正常功能调用优化之间是否存在任何区别