2015-12-30 6 views
0

Не могли бы вы предложить безопасное удаление элемента std :: vector в случаях: 1. Очистить все элементы вектора; 2. Стереть один элемент в зависимости от состояния.Защитные элементы для удаления контейнера

Какие опасности этого кода:

typename std::vector<T*>::iterator it; 
    for (it=std::vector<T*>::begin();it!=std::vector<T*>::end();it++) 
    { 
     if (*it) delete *it; 
    } 

Спасибо годов.

+2

Я мог бы. Но вы не дали понять, на что вы на самом деле застряли. – doctorlove

+0

Посмотрите, что делает 'delete'. Код построен на суевериях и предрассудках. Затем изучите урок. Программирование - это не акт веры. –

+1

Ther не нужно 'if (* it)'. – Rabbid76

ответ

2

Вы не удаляете элемент из вектора. Таким образом, векторный элемент указывает на местоположение, как раньше, т. Е. Тот же T. Однако, поскольку вы удалили это T, вы больше не можете разыскивать указатель - это будет UB и может привести к сбою вашей программы.

delete вызывает деструктор T (отлично, это то, что вы должны делать), но delete не меняет вектор. Следовательно, итератор действителен все время.

Либо вы должны удалить элемент, для которого вы вызвали delete, или, по крайней мере, установить векторный элемент в nullptr.

typename std::vector<T*>::iterator it; 
for (it=std::vector<T*>::begin();it!=std::vector<T*>::end();it++) 
{ 
    delete *it; 
    *it = nullptr; // Only needed when you don't erase the vector element 
} 

Это решение требует, чтобы вы всегда проверять nullptr перед использованием любого элемента вектора.

В большинстве случаев лучшим решением является удаление элемента из вектора.

В случае, если вы уничтожаете все элементы, вызывая delete на каждый элемент, просто вызовите clear на вектор после цикла.

+0

Да, я согласен - но что такое итератор? Действует ли оно после удаления? А что такое C++ 11? Каковы другие варианты? –

+2

Да - итератор действителен, потому что вы не удаляли никаких элементов в векторе. Удалить вызывает деструктор T, но не меняет вектор. – 4386427

1

Например, для вас первые два вопроса, которые появились рассматривать клиринговых такой вектор

std::vector<int> v;//maybe have elements or not... 
  1. Clear вектор по телефону clear

    v.clear(); 
    
  2. Если вы хотите, чтобы удалить элементы в то время как вы идете по вектору, который удовлетворяет условию (т.е. предикату), используя v.erase(it), вам нужно быть осторожным. К счастью, erase возвращает итератор после снятого положения, так что-то вроде

    for (auto it=v.begin();it!=v.end();) 
    { 
        if (predicate(it)) 
         it = v.erase(it); 
        else 
         ++it; 
    } 
    

    Очевидно, что вы можете использовать std::remove_if вместо (с std::erase), если вы хотите немного сжать ваш вектор, избегая «очень производительную рукописную remove_if» как об этом говорил комментатор.

Если вы хотите удалить вещи, как вы круглую петлю, вы можете вручную сделать петлю, самостоятельно или использовать алгоритм - но умные указатели сделать гораздо больше смысла. Я подозреваю, что вы : хотите удалить элементы, возможно, в дополнение к сокращению вектора, так как вы сказали «Я обнаружил, что элемент этого вектора можно использовать после его удаления». Если вы хотите сохранить сырые указатели в контейнере, то только delete пунктов, вы не используете if в предложенном вами коде. Вы должны учитывать, когда планируете это делать.
Примечание: изменение содержимого итератора не отменяет итератор.

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

+0

Downvote для ужасно исполняемого рукописного слова remove_if. – SergeyA

Смежные вопросы