Почему Objective-C включает полное имя типа C ++ в виде строки в двоичном файле? Могу ли я избавиться от этого? - PullRequest
1 голос
/ 01 апреля 2019

Когда я добавляю тип C ++ в качестве ивара Objective-C, я получаю полное имя этого типа в виде строки:

@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, составляет около 1 КБ. Какова цель этого и можно ли от него избавиться?

1 Ответ

1 голос
/ 01 апреля 2019

Эта информация требуется для кодировки типов, используемой средой выполнения 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> > > > > >}}

И, конечно, вы можете пойти дальше, сделав рамку void * и приведя ее по мере необходимости, или, возможно, скрыв ее за более простым типом C ++ и pimpl (я не пробовал этот подход, чтобы увидеть, работает ли он) , Но если вы поместите C ++ (или что-то еще) непосредственно в ивар ObjC, он должен сохранить имя типа для среды выполнения.

...