удалить динамически выделенный объект из std :: vector

Это правильно?:

std::vector<Enemy*> enemies;
enemies.push_back(new Enemy());

Enemy* enemy = enemies[0];
enemies.erase(enemies.begin() + 0);
delete enemy;

person Ryan    schedule 26.03.2011    source источник
comment
Как обычно: рассмотрите возможность использования вектора общих указателей или boost::ptr_vector.   -  person Björn Pollex    schedule 27.03.2011
comment
Вот ссылка на контейнеры указателей ускорения, о которых говорит Space_C0wb0y: boost.org/doc/libs/1_46_1/libs/ptr_container/doc/   -  person yasouser    schedule 27.03.2011
comment
Вы push_back(new Enemy)? Разве вы не знали, что толкать врага в спину несправедливо? :-D   -  person P Shved    schedule 27.03.2011
comment
@Pavel: Не только несправедливо, но и неразумно: Держите друзей ближе, а врагов - ближе.   -  person Björn Pollex    schedule 27.03.2011


Ответы (4)


Да, это работает, но это не идеальный подход.

Во-первых, добавление 0 - это просто шум, его можно убрать. Но даже лучше, просто используйте pop_front(). Кроме того, нет необходимости в промежуточном шаге, вы можете удалить его перед удалением.

Но std::vector не подходит для того, чтобы появляться спереди, особенно если он большой (потому что оставшиеся элементы нужно сдвинуть, чтобы заполнить пустоту). Если вам не нужна непрерывная память, используйте вместо нее std::deque. Или, если порядок не имеет значения, вы можете использовать что-то вроде этого:

template <typename T, typename A>
void unordered_pop_front(std::vector<T, A>& vec)
{
    using std::swap;
    swap(vec.front(), vec.back()); // constant time

    vec.pop_back(); // constant time
}

Он меняет местами передний элемент на задний элемент, а затем снимает его. Конечно, порядок не соблюдается.

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

Используйте либо Boost ptr_vector, либо std::vector умных указателей. (Примечание: не используйте std::auto_ptr в контейнере, в этом отношении он не работает.) Для быстрого предложения умного указателя используйте либо std::unique_ptr (если ваш компилятор поддерживает C ++ 0x), либо std::/boost::shared_ptr.

person GManNickG    schedule 26.03.2011

std::vector<Enemy*> enemies;
enemies.push_back(new Enemy());

Это не безопасно. Если push_back не удается выделить достаточно памяти для размещения нового указателя, происходит утечка объекта Enemy.

Использование вектора интеллектуальных указателей может решить эту проблему, но в противном случае вы должны зарезервировать пространство в векторе, прежде чем возвращаться:

std::vector<Enemy*> enemies;
enemies.reserve(1);    // or more generally, enemies.reserve(enemies.size()+1);
enemies.push_back(new Enemy());

Теперь мы знаем, что push_back не может не выделить память, и если reserve не удается, то исключение выдается до создания Enemy.

person Steve Jessop    schedule 26.03.2011

Конечно, мне нравится. Вам не нужен + 0 в строке enemies.erase, но в остальном это нормально.

person Karl Nicoll    schedule 26.03.2011

Да, это нормально. Можно немного упростить:

delete enemies[0];
enemies.clear();

Для удаления элемента вы также можете использовать:

enemies.pop_back();

или (очень похоже на ваш):

enemies.erase(enemies.begin());
person Matthew Flaschen    schedule 26.03.2011
comment
Что вызывает ~ Enemy ()? Это vector.erase () / vector.clear () или это удаляемые враги [0]? - person Ryan; 27.03.2011
comment
@Ryan: delete вызывает деструктор указанного объекта, затем освобождает память. - person GManNickG; 27.03.2011