В C++ 2003 модель распределителя сломана, и на самом деле нет правильного решения. Для C++ 2011 модель распределителя была исправлена, и вы можете иметь для каждого распределителя экземпляров, которые распространяются до содержащихся объектов (если, конечно, вы не захотите их заменить). Как правило, для того, чтобы это было полезно, вы, вероятно, захотите использовать динамически полиморфный тип распределителя, который по умолчанию не нужен std::allocator<T>
(и обычно я ожидал бы, что он не будет динамически полиморфным, хотя это может быть лучшим выбором реализации). Тем не менее, [почти] все классы стандартной библиотеки C++, которые занимают выделение памяти, являются шаблонами, которые используют тип распределителя как аргумент шаблона (например, IOStreams являются исключением, но обычно они не выделяют никакого интересного количества памяти, чтобы гарантировать добавление поддержки распределителя).
В нескольких ваших комментариях вы настаиваете на том, что распределители действительно должны быть глобальными: это определенно неверно. Каждый тип, поддерживающий распределитель, хранит копию предоставленного распределителя (по крайней мере, если у него есть данные уровня экземпляра, а если нет, то нет ничего, что можно было бы сохранить, например, в случае с распределителем по умолчанию с использованием operator new()
и operator delete()
) , Это фактически означает, что механизм распределения, предоставляемый объекту, должен придерживаться до тех пор, пока он использует активный распределитель. Этот может быть выполнен с использованием глобального объекта, но он также может быть выполнен с использованием, например, подсчет ссылок или связывание распределителя с объектом, содержащим все объекты, которым он задан. Например, если каждый «документ» (думаю, XML, Excel, Pages, любой файл структуры) передает распределитель своим членам, распределитель может жить как член документа и уничтожаться, когда документ уничтожается после уничтожения его содержимого , Эта часть модели распределителя должна работать с классами pre-C++ 2011, если они также принимают аргумент распределителя. Однако в классах pre-C++ 2011 распределитель не будет передаваться содержащимся объектам. Например, если вы предоставите распределитель для std::vector<std::string>
, версия C++ 2011 создаст std::string
с использованием распределителя, присвоенного std::vector<std::string>
, соответствующим образом преобразованным в сделку с std::string
с.Этого не произойдет с распределителями pre-C++ 2011.
Чтобы на самом деле использовать распределители в подсистеме, вам действительно необходимо передать их, либо явно, как аргумент для ваших функций, и/или классов, либо неявно с помощью объектов-распределителей, которые служат в качестве контекста. Например, если вы используете какой-либо из стандартных контейнеров в качестве [части] контекста, который передается, вы можете получить использованный распределитель, используя его метод get_allocator()
.
Почему распределитель должен быть глобальным? Пока каждый выделенный блок имеет ссылку на свой собственный распределитель, чтобы его можно было правильно освободить, имеет ли значение, где собственно распределитель? –
Где бы распределитель ушел на выделенную единицу? Мне кажется, что это должно быть глобально. – chadb