Вы можете прочитать о спецификации для распределителей здесь: https://en.cppreference.com/w/cpp/named_req/Allocator. Они немного изменились в разных стандартных версиях, но я напишу о представлениях C ++ 17 и 20.
Когда вы выделяете память с помощью распределителя a1
, она может быть освобождена только другим распределителем a2
если a1 == a2
. Цитата из стандарта :
a1 == a2
возвращает true
только в том случае, если память, выделенная из каждого, может быть освобождена через другого.
std::allocator<T>
обычно реализуется как пустой тип без состояния. std::allocator<T>::is_always_equal::value
равно true
, поэтому все std::allocator<T>
объекты равны. Таким образом, оба освобождения четко определены.
Если это был распределитель с сохранением состояния, то после AllocatorT a3 = a1
, a1 == a3
должно быть true
, так что вы можете безопасно освободить его. AllocatorT a2;
default создает его, а a2 == a1
это , вероятно, не true, поэтому вы не можете освободить с помощью a2
.
В C ++ 17 вы также можете сделать AllocatorT a3 = std::move(a1);
. Это означает, что вы больше не можете освобождать с a1
(если только a1 == a3
после хода), но только с a3
. Это было изменено в C ++ 20, поэтому вы можете копировать только распределители.
В настоящее время большинство реализаций контейнеров содержат объект, который наследуется от распределителя, поэтому, если он пуст, пустая базовая оптимизация используется для того, чтобы не занимать лишних байтов. Таким образом, даже если все объекты всегда одинаковы, не мешает использовать 0 дополнительных байтов для хранения распределителя (и если он является состоящим, в любом случае объект должен быть сохранен для освобождения). В C ++ 20 это, вероятно, будет реализовано с атрибутом [[no_unique_address]]
для того же эффекта.