#include <memory>
struct foo { };
int main() { std::make_shared<foo>(); }
Run Code Online (Sandbox Code Playgroud)
由这两个所产生的asssembly g++7和clang++5与-fno-exceptions -Ofast上面的代码:
包含对单个呼叫operator new,如果-fno-rtti是未通过.
包含两个单独的呼叫到operator new如果-fno-rtti被通过.
这可以在gcc.godbolt.org (clang++5版本)上轻松验证:
为什么会这样?为什么禁用RTTI会阻止make_shared统一对象和控制块分配?
Use*_*ess 12
为什么禁用RTTI会阻止make_shared统一对象和控制块分配?
您可以从汇编程序中看到(只是粘贴文本非常适合链接和拍照),统一版本不会分配简单foo但是a std::_Sp_counted_ptr_inplace,而且该类型有vtable(回想一下它需要一个一般的虚拟析构函数,以应对自定义删除器)
mov QWORD PTR [rax], OFFSET FLAT:
vtable for
std::_Sp_counted_ptr_inplace<foo, std::allocator<foo>,
(__gnu_cxx::_Lock_policy)2>+16
Run Code Online (Sandbox Code Playgroud)
如果禁用RTTI,则无法生成就地计数指针,因为它必须是虚拟的.
请注意,非就位版本仍然引用vtable,但它似乎只是直接存储去虚拟化的析构函数地址.
Whi*_*TiM 11
当然,std::shared_ptr将在编译器支持的假设下实现rtti.但它可以在没有它的情况下实施.请参阅没有RTTI的shared_ptr?.
从这个旧的GCC的libstdc ++ #42019错误中得到启示.我们可以看到Jonathan Wakely在没有RTTI的情况下添加了一个修复程序.
在GCC的libstdc ++中,std::make_shared使用其服务std::allocated_shared使用非标准构造函数(如下面的代码所示).
如此补丁中所示,从第753行可以看出,获取默认删除器只需要使用typeid 如果启用RTTI的服务,否则,它需要一个不依赖于RTTI 的单独分配.
编辑: 9 - 2017年5月:删除此前发布的受版权保护的代码
我没有调查libcxx,但我想相信他们做了类似的事情....
没有充分的理由.这看起来像libstdc ++中的QoI问题.
使用clang 4.0,libc ++没有这个问题.,而libstdc ++确实如此.
使用RTTI的libstdc ++实现依赖于get_deleter:
void* __p = _M_refcount._M_get_deleter(typeid(__tag));
_M_ptr = static_cast<_Tp*>(__p);
__enable_shared_from_this_helper(_M_refcount, _M_ptr, _M_ptr);
_M_ptr = static_cast<_Tp*>(__p);
Run Code Online (Sandbox Code Playgroud)
一般来说,get_deleter没有RTTI就无法实现.
它似乎正在使用删除器位置和标记来存储T此实现.
基本上,使用的是RTTI版本get_deleter. get_deleter依赖于RTTI.获取make_shared无劳动RTTI需要重写它,并且他们采取了导致它做的两个拨款的简单的路线.
make_shared统一T和引用计数块.我想有两个可变大小的删除器和可变大小的T东西变得讨厌,所以他们重用了删除器的可变大小的块来存储T.
get_deleter未执行RTTI并返回a 的修改后的(内部)void*可能足以从此删除器中执行所需操作; 但可能不是.
| 归档时间: |
|
| 查看次数: |
1393 次 |
| 最近记录: |