没有运行时类型信息的 shared_ptr?

7

我正在尝试在一个使用xc32 1.34(gcc 4.5.2的衍生版本)构建的嵌入式项目中使用shared_ptr。该项目已使用-fno-rtti禁用RTTI。

#include <memory>

仅包含头文件会导致以下错误:

/Applications/microchip/xc32/v1.34/bin/bin/../../lib/gcc/pic32mx/4.5.2/../../../../pic32mx/include/Cpp/memory: In member function 'virtual void* std::tr1::_Ref_count_del<_Ty, _Dx>::_Get_deleter(const std::type_info&) const':
In file included from APP/MODULES/LIGHT_MANAGER/LightManager.cpp:13:0:
/Applications/microchip/xc32/v1.34/bin/bin/../../lib/gcc/pic32mx/4.5.2/../../../../pic32mx/include/Cpp/memory:1264:39: error: cannot use typeid with -fno-rtti
/Applications/microchip/xc32/v1.34/bin/bin/../../lib/gcc/pic32mx/4.5.2/../../../../pic32mx/include/Cpp/memory: In member function 'virtual void* std::tr1::_Ref_count_del_alloc<_Ty, _Dx, _Alloc>::_Get_deleter(const std::type_info&) const':
/Applications/microchip/xc32/v1.34/bin/bin/../../lib/gcc/pic32mx/4.5.2/../../../../pic32mx/include/Cpp/memory:1299:39: error: cannot use typeid with -fno-rtti
/Applications/microchip/xc32/v1.34/bin/bin/../../lib/gcc/pic32mx/4.5.2/../../../../pic32mx/include/Cpp/memory: In function '_Dx* std::tr1::get_deleter(const std::tr1::shared_ptr<_Ty2>&)':
/Applications/microchip/xc32/v1.34/bin/bin/../../lib/gcc/pic32mx/4.5.2/../../../../pic32mx/include/Cpp/memory:1956:44: error: cannot use typeid with -fno-rtti

所以我的问题是:通常在没有RTTI的情况下使用shared_ptr是不可能的吗?还是我做错了什么?

1
没有运行时类型信息的 C++ 不再是 C++。所有(我是说 所有)的赌注都是无效的。谁能保证你可以在没有运行时类型信息的情况下使用 <algorithm><vector><cstdio> - n. m.
3
RTTI 不是类型擦除所必需的。通常的模式是使用一个模板包装类实现一个抽象类。 - Quentin
1
话虽如此,g++ 5.4.0在关闭rtti的情况下可以轻松处理shared ptrs。 - n. m.
1
@n.m. 4.8.5 也应该。根据这个 https://gcc.gnu.org/ml/gcc-patches/2014-12/msg01159.html - Sergei Nikulov
1
@nwp 我可能说得太笼统了。我的意思是,GCC的-fno-rtti(似乎是这里的问题)只会删除typeiddynamic_cast和其他可以检索对象类型的工具。虚函数仍然可以正常工作。 - Quentin
显示剩余7条评论
1个回答

8
问题出在get_deleter自由函数上:
template<class D, class T> D* get_deleter(const shared_ptr<T>& p) noexcept;

Returns: If p owns a deleter d of type cv-unqualified D, returns std:addressof(d); otherwise returns nullptr. The returned pointer remains valid as long as there exists a shared_ptr instance that owns d.

显然,最直接的实现方法是将删除器的“类型id”存储在控制块中。虽然还有其他可能的实现方法,但它们会(a)更加复杂,(b)失去与启用RTTI的代码的二进制兼容性,以及(c)违反了“-fno-rtti”的“精神”。
另一个有问题的函数是“dynamic_pointer_cast”,它对存储的指针调用“dynamic_cast”。
然而,“shared_ptr”的主要功能可以在不使用RTTI特性的情况下实现,正如Sergei Nikulov在上面提到的那样,gcc 4.8.5附带的“shared_ptr”可以与“-fno-rtti”一起使用,除了“get_deleter”和“dynamic_pointer_cast”函数之外;只要您不使用这些功能,您就可以使用“shared_ptr”。这可以与例如“any”进行对比,后者在没有使用“typeid”的情况下无法实现。
您的供应商有责任提供一个在所有配置下都可以工作的标准库,包括非标准的库,如果他们支持使用非标准的库。然而,如果您的供应商不合作,您仍然有几个选择:
- 修补所提供的标准库以删除损坏的“get_deleter”代码; - 使用替代标准库(例如更新的libstdc++或libc++); - 使用替代智能指针工具(例如Boost)或编写自己的智能指针工具。

1
我意识到这是一个旧答案,但是std::any可以在没有RTTI的情况下实现。请参见此处。只要不使用type成员函数即可。 - Paul Rooney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接