Строя контейнеры под свой гейм проект,
установил некоторые правила, которые распростроняются и на STL контейнеры
1. Не передавайте в контейнер обьект по оператору new если не собираетесь его удалять через delete
2. Старайтесь не использовать контейнер обьектов, если добавляете обьекты на стёке, перфоманс падает на конструкции и деструкции на стёке + конструкции или копировании в самом контейнере. Используйте контейнер указателей на обьекты.
24 января 2009 г.
Подписаться на:
Комментарии к сообщению (Atom)
А можно поучаствовать в конкурсе самых банальных правил? Вот, например:
ОтветитьУдалить3. Не создавайте контейнеры содержащие auto_ptr
4. Используйте empty() вместо size()==0
5. Позаботтесь об написании соответствующих копирующих конструкторов для классов, которые используют указатели на динамически создаваемые объекты...
Да :) Это как-то пропустил, думал и так понятно.
ОтветитьУдалитьОсобенно про копирующие конструкторы, тут важно тонкое понимание.
Ну так а я о чем?
ОтветитьУдалитьВот твое первое правило. Разве не понятно, что созданные в куче объекты сами не удаляются? И здесь никакое тонкое понимание не нужно. Это основы
А второе? Вообще очень странная связь между стеком и указателями и просто катастрофическое заблуждение!
"Старайтесь не использовать контейнер обьектов, если добавляете обьекты на стёке, ... Используйте контейнер указателей на обьекты."
Браво! Если коротко, то ты написал: "Используйте контейнеры, содержащие указатели на автоматические объекты!". А если автоматические объекты уйдут из области видимости раньше контейнера? Это тебя не смущает? И еще:
"перфоманс падает на конструкции и деструкции на стёке + конструкции или копировании в самом контейнере"
Это специфика автоматических объектов, понимаешь-ли. Если ты планируешь использовать их дольше их времени жизни, то их обязательно нужно скопировать! А если ты их планируешь использовать их не дольше их времени жизни, то намного проще обходится без контейнеров.
Вот это тонкое понимание. Нужно хорошо понимать разницу между автоматическими, статическими и динамическими объектами и применять те из них, которые больше отвечают требованиям, а не пытаться использовать объекты в неестественным для них образом. Если необходимо произвольное время жизни, то нужно использовать динамические объекты, а не пытаться симулировать их поведение путем явного вызова деструкторов для автоматических объектов. И если время жизни объекта ограничено некоторым блоком, то лучше сделать его автоматическим, а не руками выделять под него память в начале блока и высвобождать в конце.
По поводу ясности правила, да хороший низкоуровневый прогер это учтёт, но никак не среднячёк, я пишу просто потому что постоянно натыкаюсь на конструкции в стороннем коде вроде:
ОтветитьУдалитьstd::vector[someObj*] objList;
objList.push_back( new someObj( ... ) );
//и далее
objList.clear();
Якобы по их мнению это очистит контейнер и деструктнрёт обьекты.
Это, да, просто я с русской терминологией не всегда возможно чёток.
Имелось в виду:
Что не рационально писать, что-то вроде:
// квадратные скобки т.к не поддерживает >, <
std::list[object] olist;
olist.push_back( object o( ... ) );
и делать это на стёке, т.е в некой функции которая может вызываться сотни раз.
проще либо указатели, либо понимание, что упадём на многократной конструкции деструкции, т.к "o" будет не просто клонирован (ctor), но
и создан и удалён в теле самого push_back + (ctor/dtor)
и того 3 вызова вместо 1 ого.
Я то как раз точно понимаю, когда и что использовать и как оно себя поведёт, вопрос понимают ли ленивые покурившие умные книжки и пропустившие шаблонную часть, или контейнерную.
Ну во-первых запись
ОтветитьУдалитьolist.push_back( object o( ... ) );
синтаксически не верна. object o( ... ) - это объявление, но никак не выражение типа object. Это основы и это стоит знать.
Во-вторых olist.push_back(...) делать можно ТОЛЬКО в некой функции и нигде более. И абсолютно не важно сотни или десятки раз ф-я вызывается - в любом случае все ее локальные данные на стеке создаются. Поэтому фраза:
"Что не рационально писать...
и делать это на стёке, т.е в некой функции ..." - полный бред. Невозможно что-либо делать не в функции!
"проще либо указатели". Ха! Указатели на автоматические объекты? Даже и не смешно! Ты это себе вообще представляешь?
list[obj*] l;
for(int i=0;i<3;i++)
{
obj k(i);//объект в стеке
i.push_back(&k);//сохраняем не объект, а указатель на него
}
//и что теперь в нашем списке? Скорее всего одинаковые адреса, доступ по которым в лучшем случае вызовет ошибку сегментации!
Такой ты выход предлагаешь? Да, ctor/dtor только по разу для объекта вызовется, ну и что с того? Смысла все равно никакого в этом нет! И не должно быть! Взятие адреса автоматических объектов - чрезвычайно чревато! И тебе, как человеку говорящему "Я то как раз точно понимаю, когда и что использовать и как оно себя поведёт", это странно не знать... Для автоматических объектов нет альтернативы кроме копирования. Это тоже стоит знать.
Если конструирование и/или копирование обходится слишком дорого - то используй альтернативные стратегии, в которых конструирование/копирование будет сведено к минимуму, или значительно удешевляться. Например, одноразовое выделение большого куска памяти и распределение его на каждый новый объект, а не многоразовое выделение маленьких кусочков.