Ответ 1
Должны ли распределители типов отскока "поддерживать" пулы памяти друг друга до тех пор, пока все они не будут уничтожены?
Короткий ответ - да, хотя, по общему признанию, с оговорками. Долгий ответ следует...
С++ 11 (и С++ 14) говорит [allocator.requirements], что my_allocator<long>
, построенный из my_allocator<int>
, должен иметь возможность удалять память, выделенную из my_allocator<int>
. Это выражается в таблице требований Allocator как:
X a(b);
с пост-условием:
Y(a) == b and a == X(b)
Как вы знаете, оператор == используется здесь для обозначения: два равных распределителя, которые могут быть освобождены друг от друга выделенными указателями. Кроме того, табличные документы, что b
является объектом типа Y
, где X
и Y
являются распределителями, связанными с rebind
, как показано выше.
Теперь это одно не отвечает на ваш точный вопрос, так как в вашем вопросе my_allocator<int>
никогда ничего не выделяет. Однако в следующей строке в этой же таблице говорится следующее о операторе распределителя ==:
a1 == a2
Пост-условие:
возвращает true только в том случае, если память, выделенная из каждого, может быть освобождена через другую. оператор == должен быть рефлексивным, симметричным и переходный и не должен выходить через исключение.
(акцент мой)
Transitive означает, что если a1 == a2 и a2 == a3, то подразумевается, что a1 == a3.
Эта деталь наделяет ваш вопрос. Первый временный my_allocator<long>
скопирован из alloc
и, таким образом, равен alloc
.
Второй временный my_allocator<long>
также скопирован из alloc
и, следовательно, также равен alloc
. Кроме того, из-за транзитивного свойства два временных my_allocator<long>
также должны быть равны друг другу.
Это не означает, что все они должны использовать один и тот же пул памяти. Но это означает, что все три из этих распределителей должны иметь возможность как-то освободить друг друга выделенными указателями. То есть ваш пример должен работать.
С++ 03 не имеет "переходного" требования. При этом добавление "переходных" к формулировке С++ 11 считалось просто "очисткой" намерения С++ 03, а не новым требованием. Поэтому юристы-юристы могут утверждать, требуется или нет транзитивность в С++ 98/03, но с практической точки зрения код лучше предположить, что это было, потому что это было целью.
В самом деле, С++ 98/03 также включал эту "ласку" (больше не в С++ 11/14):
Все экземпляры данного типа распределителя должны быть взаимозаменяемы и всегда сравниваются друг с другом.
т.е. Контейнеры С++ 98/03 допускали, что все экземпляры (действительно даже экземпляры отскока) всегда равны. Официальная поддержка "stateful" распределителей действительно не началась до С++ 11.