Подтвердить что ты не робот

Почему в С++ 11 (с использованием распределителей) может возникнуть проблема с заменой стандартных контейнеров библиотек?

Примечание. Первоначально задается GreenScape как comment.


После чтения Почему функции элемента свопинга в контейнерах STL не объявлены noexcept? кажется, что причина потенциального поведения undefined при выполнении a.swap(b) для стандартного контейнеры сводятся к тому, что они также заменяют или не заменяют базовые распределители.

  • Почему коммутаторы распределения вместе с данными проблематичны?
4b9b3361

Ответ 1

Пусть начнется, врываясь в стандарт (N3797):

23.2.1p9 Общие требования к контейнерам [container.requirements.general]

Если   allocator_traits<allocator_type>::propagate_on_container_swap::value  true, то распределители a и b также должны быть обменены   используя неквалифицированный вызов не-члену swap. В противном случае они должны   не меняются местами, а поведение undefined, если только a.get_allocator() == b.get_allocator().


Какова цель propagate_on_container_swap?

Если у Allocator есть typedef с именем propagate_on_container_swap, который ссылается на std::true_type, базовые Распределители из двух контейнеров, подлежащих обмену, также будут заменены. [1]

Если propagate_on_container_swap есть std::false_type, данные данных двух контейнеров будут меняться, но распределители останутся на своем месте.

[1] Это означает, что после a.swap(b) a.get_allocator() будет то, что было ранее b.get_allocator(); распределители поменялись местами.


Каковы последствия выносливости с учетом состояния?

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

С++ 03 не разрешал назначаемые с точки зрения состояния распределители в стандартных контейнерах, но С++ 11 требует, чтобы такая поддержка присутствовала. Это означает, что мы могли бы определить распределитель, который в зависимости от того, как он сконструирован, действует определенным образом.

Если распределитель имеет propagate_on_container_swap::value, равный false, разница в состоянии между двумя задействованными распределителями может привести к поведению undefined, поскольку один экземпляр Allocator может быть несовместим с данными, обрабатываемыми другим.


Что может быть проблемой с генераторами с сохранением состояния, если они не правильно заменены?

Скажем, у нас есть MagicAllocator, который либо использует malloc, либо operator new для распределения памяти в зависимости от того, как она была построена.

Если он использует malloc для выделения памяти, он должен использовать free для его освобождения, а в случае operator new требуется delete; из-за этого он должен поддерживать некоторую информацию, говорящую о том, какой из них должен использовать.

Если у нас есть два std::vector, которые используют MagicAllocator, но с разными состояниями (это означает, что один использует malloc и другой operator new), и мы не заменяем распределители на a.swap(b) распределителем не будет соответствовать памяти, выделенной для элементов в двух векторах после swap - что в терминах означает, что неправильный free/delete может быть вызван при освобождении.