ios - 为什么 Objective-C 将完整的 C++ 类型名称作为字符串包含在二进制文件中?我可以摆脱它吗?
问题描述
当我将 C++ 类型添加为 Objective-C ivar 时,我会以字符串形式获得该类型的全名:
@interface Test {
std::vector<int> _vector;
std::unordered_map<int, std::vector<std::string>> _map;
}
@end
@implementation Test
@end
结果是:
.L__unnamed_2:
.asciz "_vector"
.L__unnamed_3:
.asciz "{vector<int, std::allocator<int> >=\"_M_impl\"{_Vector_impl=\"_M_start\"^i\"_M_finish\"^i\"_M_end_of_storage\"^i}}"
__objc_ivar_offset_value_Test._vector:
.long 0 # 0x0
.L__unnamed_4:
.asciz "_map"
.L__unnamed_5:
.asciz "{unordered_map<int, std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > >, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const int, std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > > > > >=\"_M_h\"{_Hashtable<int, std::pair<const int, std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const int, std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > > > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >=\"_M_buckets\"^^{_Hash_node_base}\"_M_bucket_count\"Q\"_M_before_begin\"{_Hash_node_base=\"_M_nxt\"^{_Hash_node_base}}\"_M_element_count\"Q\"_M_rehash_policy\"{_Prime_rehash_policy=\"_M_max_load_factor\"f\"_M_next_resize\"Q}\"_M_single_bucket\"^{_Hash_node_base}}}"
编译器资源管理器链接— 请注意,我使用的是-Os
.
后一个,使用std::unordered_map
,大约是 1kb。这样做的目的是什么,我可以摆脱它吗?
解决方案
该信息是 Objective-C 运行时使用的类型编码所必需的,并且是动态调度工作方式的一部分。它可以通过询问运行时来检索:
Ivar *ivars = class_copyIvarList([Test class], NULL);
printf("%s\n", ivar_getTypeEncoding(ivars[1]));
free(ivars); ivars = NULL;
为了消除它,您需要避免将 C++ 类型直接放在 ObjC 对象中。您可以通过装箱在一定程度上减少冗长:
class Box {
std::vector<int> _vector;
std::unordered_map<int, std::vector<std::string> > *_map;
};
@interface Test: NSObject {
Box box;
}
@end
产量
{Box="_vector"{vector<int, std::__1::allocator<int>
>="__begin_"^i"__end_"^i"__end_cap_"{__compressed_pair<int *,
std::__1::allocator<int> >="__value_"^i}}"_map"^{unordered_map<int,
std::__1::vector<std::__1::basic_string<char>,
std::__1::allocator<std::__1::basic_string<char> > >, std::__1::hash<int>,
std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<const int,
std::__1::vector<std::__1::basic_string<char>,
std::__1::allocator<std::__1::basic_string<char> > > > > >}}
指向盒子的指针要小一些:
^{Box={vector<int, std::__1::allocator<int> >=^i^i{__compressed_pair<int *,
std::__1::allocator<int> >=^i}}^{unordered_map<int,
std::__1::vector<std::__1::basic_string<char>,
std::__1::allocator<std::__1::basic_string<char> > >, std::__1::hash<int>,
std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<const int,
std::__1::vector<std::__1::basic_string<char>,
std::__1::allocator<std::__1::basic_string<char> > > > > >}}
当然,您可以通过制作盒子 avoid *
并根据需要进行强制转换,或者可能将其隐藏在更简单的 C++ 类型和 pimpl 后面(我没有尝试过这种方法来查看它是否有效),从而走得更远。但是,如果您将 C++(或其他任何东西)直接放在 ObjC ivar 中,它必须存储运行时类型的名称。
推荐阅读
- java - 如何在 Java 中禁用 chrome webdriver 上的调试器?
- c - 允许确定哪个 PID 正在使用它们的跨平台同步原语
- c++ - OpenGL 存在于 minGW 文件夹中,但 CLion 无法访问/看到它
- javascript - 将 json 数据从一个 vue 页面传递到另一个 vue 页面并渲染图表
- jquery - 跨域 ajax 请求中的预检标头未解决授权标头
- json - Android - 使用 Retrofit 解析没有数组名称的 JSON
- javascript - 如何在表格行中显示特定图标?
- mulesoft - Mule 4 响应命名和扩展配置
- r - R:从另一个数据框中检索数据框名称
- qml - 如何在 QML ScrollView 中为滚动设置动画?