2016-03-31 2 views
0

Я создал эту функцию, которая работает с векторами, связанными списками и двойными связанными списками. Функция принимает значение и ищет его в контейнере. Если vlaue находится в контейнере, то функция будет вставлять значение рядом с тем, где оно уже существует. Итак, если val=2, то {3,2,5} станет {3,2,2,5}. Но если значение не существует в контейнере, оно добавляется обратно обратно.EXC Плохой доступ с итераторами

Я написал эту функцию, используя итераторы. Он отлично работает с вектором, однако, когда я пытаюсь запустить его со списком или двойным связанным списком, я получаю ошибку «Исправить ошибки» в строке if (*it==val). Я не вижу, что я сделал неправильно.

template <class Container, class T> 
void insertNextTo(Container &x, const T &val){ 
    typename Container::iterator it = x.begin(); 
    while (it!=x.end() && *it!=val){ 
     ++it; 
    } 
    if (*it == val){ 
     x.insert(it, val); 
    } 
    else{ 
     x.push_back(val); 
    } 
} 

Редактировать: Спасибо всем! Ваше предложение изменить заявление if отлично работало!

+0

Если 'val' не найден, то условие' if' приводит к тому, что конечный элемент приводит к UB. – Mahesh

ответ

2

Изменить

if (*it == val) 

к:

if (it != x.end()) 

Если val не найден в контейнере, цикл завершится, когда it == x.end(). Это указывает на конец массива, поэтому опосредование через него приводит к неопределенному поведению.

0

Кто-то исправит меня, если я ошибаюсь, но я считаю, что ваша ошибка исходит из того факта, что когда ваш итератор достигает конца списка, он фактически указывает на адрес после последнего бит списка в памяти, который может быть или не быть инициализирован и в области действия, что приводит к ошибке вашей программы.

2

Если значение еще не указано, it будет равно end(), когда цикл закончен, и вы не можете разыменовать end(). Вам нужно изменить if (*it == val) к if (it != x.end()) вместо:

//if (*it == val){ 
if (it != x.end()){ 
    x.insert(it, val); 
} 

В качестве альтернативы, так как вы только вставляя одно значение, если вы найдете val, то вы можете сделать insert() и выйти из функции сразу, а затем push_back() только тогда, когда цикл достигает конец контейнера:

template <class Container, class T> 
void insertNextTo(Container &x, const T &val) { 
    typename Container::iterator it = x.begin(); 
    while (it != x.end()) { 
     if (*it == val) { 
      x.insert(it, val); 
      return; 
     } 
     ++it; 
    } 
    x.push_back(val); 
} 

В этом случае, вы можете упростить код, используя std::find() вместо ручного цикла:

#include <algorithm> 

template <class Container, class T> 
void insertNextTo(Container &x, const T &val) { 
    typename Container::iterator it = std::find(x.begin(), x.end(), val); 
    if (it != x.end()) { 
     x.insert(it, val); 
    } else { 
     x.push_back(val); 
    } 
} 

Или даже это, так как это безопасно insert() используя end() итератор, это фактически то же самое, как push_back():

template <class Container, class T> 
void insertNextTo(Container &x, const T &val) { 
    typename Container::iterator it = std::find(x.begin(), x.end(), val); 
    x.insert(it, val); 
} 
Смежные вопросы