auto ar = wrap({a,b,c});
Это создает временный массив типа int[3]
, затем привязывает initializer_list<int>
к этому массиву, затем вызывает wrap
, который создает array<const int>
, ссылающийся на массив.
В конце выражения массив уничтожается, оставляя array<const int>
с оборванным указателем, так что это поведение undefined:
std::cout<< ar[2] << std::endl;
Это также относится к коду в main
, переменная a
содержит висячий указатель, а a[2]
является неопределенным поведением.
Вы можете проверить это, заменив массив int
массивом типов, которые выделяют память, чтобы valgrind или asan заметили ошибку:
using V = std::vector<int>;
auto a = wrap({V{1}, V{2}, V{3}});
std::cout<< a[2].front() << std::endl;
Теперь a[2]
является объектом std::vector<int>
, но попытка доступа к его члену front()
приводит к аварийному завершению программы:
==28356==ERROR: AddressSanitizer: heap-use-after-free on address 0x60200000efb0 at pc 0x000000401205 bp 0x7fffa46f2900 sp 0x7fffa46f28f8
READ of size 4 at 0x60200000efb0 thread T0
#0 0x401204 in main /tmp/il.cc:28
#1 0x3236e21d64 in __libc_start_main (/lib64/libc.so.6+0x3236e21d64)
#2 0x400ec8 (/tmp/a.out+0x400ec8)
...
Или с валгриндом:
==28364== Invalid read of size 4
==28364== at 0x400C72: main (il.cc:28)
==28364== Address 0x51dfd20 is 0 bytes inside a block of size 4 free'd
==28364== at 0x4A07991: operator delete(void*) (vg_replace_malloc.c:502)
==28364== by 0x4013BF: __gnu_cxx::new_allocator<int>::deallocate(int*, unsigned long) (new_allocator.h:110)
==28364== by 0x4012F8: std::allocator_traits<std::allocator<int> >::deallocate(std::allocator<int>&, int*, unsigned long) (alloc_traits.h:386)
==28364== by 0x4011B1: std::_Vector_base<int, std::allocator<int> >::_M_deallocate(int*, unsigned long) (stl_vector.h:178)
==28364== by 0x40102A: std::_Vector_base<int, std::allocator<int> >::~_Vector_base() (stl_vector.h:160)
==28364== by 0x400EC4: std::vector<int, std::allocator<int> >::~vector() (stl_vector.h:425)
==28364== by 0x400C2A: main (il.cc:27)
Побочный вопрос; если бы я попытался вернуть свой обернутый массив в тесте, список инициализаторов {a,b,c}
вышел бы за пределы области видимости, и массив, который я возвращаю, был бы недействителен - это правильно?
Это уже выходит за рамки и ar
уже недействительно еще до того, как вы его вернете.
person
Jonathan Wakely
schedule
16.03.2015
inline
в определении шаблона. Я думаю, что я также помню из стандартов кодирования C ++ Саттера и Александреску, что часто бесполезно объявлять свои функции встроенными, поскольку это только указание для компилятора, и чаще всего компилятор умнее вас. - person Stephane Rolland   schedule 16.03.2015