Перегруженная функция внутри конструктора, вызывающая ошибку

Хотя я знаю, что это глупая идея, я хотел посмотреть, смогу ли я использовать один класс для контейнерных и неконтейнерных типов. Сначала я скопировал код из этого вопрос.

Тогда у меня есть две вспомогательные функции: одна для определения типа члена функции переменные (независимо от того, T имеет член value_type) и другой, чтобы определить возвращаемое значение operator *,

template <typename T>
typename std::enable_if<HasValueType<T>::value, typename T::value_type>::type
proxy_func_op() {

}

template <typename T>
typename std::enable_if<!HasValueType<T>::value, T>::type
proxy_func_op() {

}

template <typename T>
typename std::enable_if<HasValueType<T>::value, typename T::const_iterator>::type
proxy_func_mem() {
}

template <typename T>
typename std::enable_if<!HasValueType<T>::value, T*>::type
proxy_func_mem() {
}

И мой класс выглядит так:

template<typename T>
class MyIterator {

cur должен быть указатель на T вместо const_iterator если T не имеет value_type член. Если это так, начало и конец не используются.

    decltype(proxy_func_mem<T>()) begin;
decltype(proxy_func_mem<T>()) end;
decltype(proxy_func_mem<T>()) cur;
public:

Это логика моей функции инициализации здесь.

    template <typename U = T>
typename std::enable_if<HasValueType<U>::value, void>::type
init(U t) {
static_assert(std::is_same<typename T::const_iterator,
decltype(proxy_func_mem<U>())>::value,
"Make sure correct function is called.");
begin = t.begin();
end = t.end();
cur = begin;
}

template <typename U = T>
typename std::enable_if<!HasValueType<U>::value, void>::type
init(U t) {
static_assert(!std::is_same<typename T::const_iterator,
decltype(proxy_func_mem<U>())>::value,
"Make sure correct function is called.");
cur = &t;
}

Я сузил проблему до этой строки. Если я удалю init<T>(t) и скопировать и вставить содержимое первой перегрузки напрямую, я получаю правильные результаты. В противном случае я получаю неверные результаты.

    explicit MyIterator(const T& t) {
init<T>(t);
}

MyIterator& operator++() {
static_assert(HasValueType<T>::value, "You cannot use this operator for non-containers.");
if (cur + 1 != end)
cur++;
return *this;
}

decltype(proxy_func_op<T>()) operator *() {
return *cur;
}
};

Например, неверный вывод:

0
0
3
4
5
h
i

Кажется, он вызывает правильную функцию. В чем проблема?

редактировать

Почему-то меняя сигнатуру функции на init(const U& t) { устраняет проблему Кто-нибудь может объяснить почему?

Код


Ошибка Valgrind:

==4117== Invalid read of size 4
==4117==    at 0x401270: MyIterator<std::vector<int, std::allocator<int> > >::operator*() (main.cpp:78)
==4117==    by 0x400E8A: main (main.cpp:87)
==4117==  Address 0x514d0a0 is 0 bytes inside a block of size 20 free'd
==4117==    at 0x4A05FD6: operator delete(void*) (vg_replace_malloc.c:480)
==4117==    by 0x401CC5: __gnu_cxx::new_allocator<int>::deallocate(int*, unsigned long) (new_allocator.h:110)
==4117==    by 0x401999: std::_Vector_base<int, std::allocator<int> >::_M_deallocate(int*, unsigned long) (stl_vector.h:174)
==4117==    by 0x4014A4: std::_Vector_base<int, std::allocator<int> >::~_Vector_base() (stl_vector.h:160)
==4117==    by 0x4011A0: std::vector<int, std::allocator<int> >::~vector() (stl_vector.h:416)
==4117==    by 0x401209: MyIterator<std::vector<int, std::allocator<int> > >::MyIterator(std::vector<int, std::allocator<int> > const&) (main.cpp:67)
==4117==    by 0x400E75: main (main.cpp:85)

Valgrind не обнаруживает ошибок, когда я не звоню init<T>(t),


0

Решение

init принятие его параметра по значению означает, что он является копией исходного объекта. Вы храните итераторы из этой копии, которая уничтожается при init возвращается. Уничтожение контейнера делает его итераторы недействительными, поэтому разыменование этих итераторов имеет неопределенное поведение.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector