Как в stl контейнерах (например std::list) получить и удалить элемент из контейнера за один вызов функции?

110
23 января 2021, 04:20

Есть ли какая-то возможность забрать элемент из std::list одновременно удаляя его (не вызывая отдельно два метода front и pop_front)? Если такого метода или возможности нет, то какова мотивация комитета не добавлять такой метод в стандарт?

// Например сделать так. 
auto val = list.take_front();
// Заместо 
auto val = list.front();
list.pop_front(); 
Answer 1

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

Поддержку же копирования или перемещения существующего элемента можно сделать тривально, например

 value_type take_front()
 {
     auto val{::std::move(front())};
     pop_front();
     return val;
 }

Но, как видите, большой экономии тут бы не вышло.

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

#include <boost/intrusive/list.hpp>
#include <cstdlib>
class tag_ItemListBaseHook;
using t_ItemListBaseHook = ::boost::intrusive::list_base_hook
<
    ::boost::intrusive::tag<tag_ItemListBaseHook>
,   ::boost::intrusive::link_mode<::boost::intrusive::safe_link>
>;
class t_Item final: public t_ItemListBaseHook
{
    private: int m_value{22};
};
using t_Items = ::boost::intrusive::list
<
    t_Item
,   ::boost::intrusive::base_hook<t_ItemListBaseHook>
,   ::boost::intrusive::constant_time_size<false>
>;
int main()
{
    t_Item item{};
    t_Items items{};
    items.push_back(item);
    items.pop_back();
    return EXIT_SUCCESS;
}
Answer 2

Как можно увидеть в описании этого класса, такого метода нет. Хотя во многих языках программирования pop как раз удаляет и сразу возвращает значение (так, например, в JavaScript'e).

Это сделано с целью предотвратить проблемы с памятью. Что, если в списке не число, а объекты кастомного класса? Возвращать ссылку на него? А он может быть уже удалён с вызовом деструктора. Накладывать ограничение на класс, чтобы у него был определён конструктор копирования? Тоже не вариант. Куда проще конечному юзеру класса (т.е, разработчику, Вам) подписать одну строку решения для своей конкретной ситуации.

На enSO несколько лет назад был такой же вопрос про std::queue, там Вы можете найти ещё больше пояснений.

READ ALSO
expected unqualified-id before &#39;-&gt;&#39; token

expected unqualified-id before '->' token

cpp- ругается на цикл где if: expected unqualified-id before '->' token, не нравится Sprite

114
Rails 6 не подключается bootstrap 4 и jQuery

Rails 6 не подключается bootstrap 4 и jQuery

Выдает после установки bootstrap 4 и jQuery в панели разработчика ошибки

156
В чем разница между div и span

В чем разница между div и span

Я новичок в программировании и хотелось бы досконально разобраться в чем разница между div и spanСтоит ли использовать только div или только span или...

132
Установка бесконечного таймера для переключения активного элемента

Установка бесконечного таймера для переключения активного элемента

Есть блок, в котором находится списокЕсть функция: при клике на элемент списка li меняется фон блока на соответствующий

114