Вся проблема в таком удобном, но таком кривом Allocator'е в системе STL, дело в том что он создает временный объект
конструируемого объекта, и никак его не исправить, чтобы он оставался совместимым с STL.
Вот простой пример:
class Base { public: Base(){ cout<<"construct\n"; } Base( Base& Copy ){ cout<<"copy construct\n"; } ~Base( ){ cout<<"destruct\n"; } }; void main( ) { std::vector<Base> vec; vec.push_back( Base( ) ); // construct + copy construct + destruct + destruct. }
Новые фичи с move конструкторами совершенно на мой взгляд не решают проблему, этож надо для всех типов не забыть сделать move или copy конструктор, что само по себе не есть гуд, да и к тому же, любое лишнее копирование не есть гуд, а оно есть даже в новомодных и бесполезных move конструкторах (имхо конечно, может кто уже успел полюбить move конструкторы и паяет их даже в структурах :))
Вся проблема конечно в самом языке C++, что он не умеет конструировать объекты дистанционно от new оператора, поэтому я лично пользуюсь собственными контейнерами с перегруженными placement new операторами, обернув эти операторы в макросы для удобства (единственный метод доставить конструктор оператору new, не создавая временный объект). В том же анриале используются исключительно перегруженные placement new для добавления элементов в массив, чем я хуже :)
Может для обычных базовых типов STL и годиться (как это обычно любят демонстрировать, те кто приводят различные примеры использования контейнеров STL), но в реале, никому не нужны массивы обычных типов (кроме указателей) :), все пользуются массивами классов и структур, а создание целого класса или структуры, только для того чтобы на основе него создать точно такой же объект, а временный объект еще надо правильно удалить, определив в нем по крайней мере copy конструктор, но и он не избавит от издержек ненужного копирования объекта, а потом еще и удаления. (новомодные move конструкторы вообще, по моему избыточный код).
В общем я использую только placement new и самопальные деструкторы Data->~T(), а память выделяю и удаляю чем то типа malloc и free, просто потому, что они делают ровно то что и требуется, они создают и удаляют объект только по запросу программиста, и ровно столько копий и столько конструкторов, сколько сказал программист.
Ну и соответственно так как однотипные Allocator'ы используются везде где только можно во всем STL, то и использование STL является для меня неприемлемым :)
Как вам такой аргумент ?
вообще не юзаю вектор для классов по значению. Не из-за принципа, а что-то вроде потребности не возникало...
всегда либо стандартный тип, либо указатель, ну или мб еще голая структура с парочкой переменных, но ничего сложнее....
djonmalkovi4
желаю тебе нарваться на кучу багов в чужих велосипедах :)
Да это весомая причина чтобы его не использовать.
И написать свой
Действительно,... какая такая необходимость хранить в векторе объекты? Уж не для того ли, чтобы создать сию тему (мы же не можем допустить мысли, что автор не умеет использовать STL по назначению)?
djonmalkovi4
> Как вам такой аргумент ?
Никак. Мне плевать на издержки создания временного объекта. Пускай компилятор оптимизирует.
djonmalkovi4
vec.emplace_back(Base( ));
же.
я в векторе храню только указатели или POD структуры.
kolobokspb
> я в векторе храню только указатели или POD структуры.
Да, возникают указатели на эти объекты (при использовании чего-то более сложного, чем POD) в других объектах. И вектор становится ненужным.
BUzer
> Никак. Мне плевать на издержки создания временного объекта. Пускай компилятор
> оптимизирует.
+1
Главное, что библиотека удобна, а скорость все равно в большей степени зависит от железа.
Почему я никогда не буду использовать лом при ремонте легкового автомобиля.
Лом, хоть и незаменимый инструмент в ремонте грузовых крупнотоннажных машин, совершенно не годится для тонкой механики легкового автомобиля.
Почитай про Boost.Intrusive. Они чуть более сложны в реализации, зато не создают временные объекты и полностью управляют циклом жизни твоих классов. STL контейнеры неинтрузивны, от этого получается много копирований. Это их свойство, его надо учитывать. Вобщем там во вступлении к Boost.Intrusive всё написано.
Вы вот хи-хи да хе-хе, а проблема, между тем, действительно существует. Например, именно из-за того, что std::list не интрузивный, а копирующий, он в качестве именно листа негоден чуть менее, чем полностью. А не в качестве листа он как-то и не особенно нужен - для стеков и очередей есть тот же вектор и deque. И получается пятое колесо - уже осадочек. А сколько ещё таких вещей в STL? Алогоритмов - чуть менее, чем все (особенно for_each). А корявые итераторы?
Беда STL в том, что её тужились сделать универсальной-преуниверсальной, да так и не сделали.
djonmalkovi4
> vec.push_back( Base() )
А так: vec.resize(vec.size()+1) ?
как бе, СТЛ универсален, и за эту универсальность надо платить...
в данном случае сложно не согласиться со slava_mib, который в одной из соседних тем боролся со сложностью, вот как раз тот случай сложности с которым надо бороться...
практически всегда, побаловавшись со своими велосипедами, я нахожу как это сделать через СТЛ не проиграв в эффективности, но сильно выиграв в количестве и понятности кода...
RPGman
> А так: vec.resize(vec.size()+1) ?
все конструкторы вызовутся сразу...
Тема в архиве.