Удалить элементы из QList указателей

У меня есть переменная QList. Как я могу стереть все элементы, начиная с индекса X, и удалить все последующие элементы N, позаботившись также об освобождении памяти?


person Stefano    schedule 12.08.2012    source источник
comment
Что такое X в вашем вопросе?   -  person Kerrek SB    schedule 13.08.2012
comment
X - мой начальный индекс, я должен иметь возможность удалить N элементов, начиная со строки X   -  person Stefano    schedule 13.08.2012


Ответы (1)


Прежде всего, вы никогда не должны использовать MyClass* для "владения" (т.е. контроля времени жизни) экземпляром MyClass. Таким образом, список MyClass* также не должен «владеть» какими-либо экземплярами MyClass. Таким образом, вы никогда не будете использовать оператор delete ни с одним из этих указателей (и случайный delete за пределами реализации умного указателя почти всегда должен вызывать удивление).

QList на самом деле является типом, оптимизированным для аналогичного варианта использования. QList<MyClass> будет внутренне хранить динамический массив MyClass* (если MyClass больше указателя), поэтому изменение порядка и расширение списка потенциально дешевле. Однако, если вам нужно удалить элементы из списка, не удаляя их, вы должны использовать QList<unique_ptr<MyClass>> или аналогичный. В любом случае вам не придется беспокоиться о времени жизни объектов; вам нужно только удалить их из списка.

Теперь, когда я это сказал, есть несколько полезных идиом STL, которые помогут достичь того, что вы ищете, и они также применимы к (большинству) контейнеров Qt (редактировать: исправлено удаление, добавлено несколько полезных комментариев< /эм>):

QList<MyClass*> myList; //TODO FIXME XXX: clarify mentioned ownership issues
assert(X + N <= myList.size());

// this is the range of objects we want to remove and delete
// (N elements, starting from index X)
auto range_begin = myList.begin() + X,
     range_end = range_begin + N;
// delete each object in range
std::for_each(range_begin, range_end, [](MyClass* ptr) { delete ptr; });
// remove them from the list
myList.erase(range_begin, range_end);

Еще проще, если вы хотели удалить все элементы после myList[X - 1] (короче говоря, заменить range_end на myList.end()).

person eq-    schedule 12.08.2012
comment
это кажется менее подверженным ошибкам, чем ответ Blood, но он использует std, и я бы придерживался только Qt. Кроме того, решение Blood использует только один цикл, в то время как здесь я должен использовать два цикла: один для удаления объекта и один для стирания элементов из списка. Однако мне больше нравится в вашем ответе тот факт, что вы используете итераторы. Есть ли способ смешать ваш ответ и ответ Blood, чтобы использовать итераторы, но с одним циклом? - person Stefano; 13.08.2012
comment
@Stefano: Да, он использует два цикла; однако другой ответ действительно использует N циклов за кулисами! Вы также должны отметить, что он не повторяется дважды в одном и том же диапазоне, потому что erase работает иначе. Если вы хотите избежать STL (и я не могу понять, почему вы должны это делать, ведь сейчас 2012 год!), вы можете заменить for_each циклом for; в использовании итераторов нет ничего общего с STL, поскольку контейнеры Qt также их поддерживают. - person eq-; 13.08.2012
comment
@Stefano: Кроме того, невозможно избежать двух циклов в том, чего вы пытаетесь достичь. Во-первых, вам нужно перебрать [range_begin, range_end), чтобы удалить элементы. Затем вам нужно пройтись по конечным элементам, чтобы переместить их назад (это то, что делает erase), и только тогда вы можете обрезать список. Это не неэффективно; это настолько оптимально, насколько это возможно. - person eq-; 13.08.2012
comment
К вашему сведению, использование QList<unique_ptr<MyClass>> будет проблематичным в Qt 4.x, который не поддерживает семантику перемещения. Реализация QList push_back принимает только const T&, но не T&&. - person Bret Kuhns; 19.12.2012