Возможно ли это сделать, не полагаясь на конкретную реализацию STL, написав собственный распределитель и / или разделив контейнер на подклассы?
Можно, но это не делает это хорошей идеей. И даже то, что вы можете, зависит от вашего компилятора / стандартной библиотеки.
До C ++ 11 распределители не могут иметь состояние . Они не могут иметь полезных членов, потому что контейнеры не обязаны фактически использовать распределитель, который вы передаете. Им разрешено создавать свои. Таким образом, вы можете установить тип распределителя, но вы не можете назначить ему конкретный распределитель экземпляр и ожидать, что этот экземпляр будет всегда использоваться.
Таким образом, ваш распределитель не может просто создать буферный объект и сохранить его внутри. Это должно было бы использовать глобальный (или частный статический или любой другой) буфер. И даже тогда несколько экземпляров будут использовать один и тот же буфер.
Вы могли бы обойти это, если бы распределитель хранил (в частных статических переменных) ряд буферных объектов и сопоставленных указателей. Это позволит вам выделить объект буфера определенного размера, и вы получите отображенный указатель обратно. Диллокатор будет использовать указатель, чтобы выяснить, из какого объекта буфера он получен, и выполнить соответствующую очистку для него.
Конечно, это было бы совершенно бесполезным для того, чтобы что-то делать с этими буферами. Вы не можете использовать буфер, который в настоящее время отображается. И если ваш распределитель удаляет буфер, как только вектор завершен с памятью, вы никогда не сможете использовать этот буферный объект для выполнения чего-либо.
Кроме того, не забывайте: отключение буфера может привести к сбою по неизвестным причинам. Если произойдет сбой, вы не сможете узнать, что это произошло, потому что вызов unmap находится в распределителе. И деструкторы не должны бросать исключения.
C ++ 11 делает так, чтобы распределители могли иметь состояние. Это означает, что это более или менее возможно. Вы можете заставить распределитель пережить std::vector
, который построил данные, и, следовательно, вы можете запросить распределитель для пост-сопоставления объекта буфера. Вы также можете хранить информацию о том, не удалось ли удалить карту.
Это все еще не делает это хорошей идеей. В целом, гораздо проще просто использовать обычный старый std::vector
и использовать glBufferSubData
для его загрузки. В конце концов, отображение буфера с помощью READ_WRITE почти гарантирует, что это будет обычная память, а не адрес GPU. Это означает, что при отображении просто будет выполняться DMA, что glBufferSubData
делает. Вы не получите большую производительность при картировании.
Перераспределение с буферными объектами будет гораздо более болезненным. Поскольку объект std::vector
определяет, какой объем дополнительной памяти хранить, вы не можете играть в такие игры, как выделение большого буферного объекта и последующее увеличение объема памяти, используемой контейнером. Каждый раз, когда std :: vector думает, что ему нужно больше памяти, вам нужно будет создать новое имя объекта буфера, а std :: Vector сделает поэлементную копию из отображенной памяти в отображенную память.
Не очень быстро.
На самом деле, вы просто хотите создать свой собственный контейнерный класс. Это не так сложно. И будет намного легче контролировать, когда он отображается, а когда нет.