| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Указатаеь на вектор векторов |
| Автор: Woo 14.4.2007, 09:53 | ||
| привет нормально ли так делать?
|
| Автор: vinter 14.4.2007, 10:27 |
| а зачем тебе это? да и выглядит как-то убого.. |
| Автор: dizzy1984 14.4.2007, 13:26 |
| Ничего плохого не вижу. Для работы с динамической памятью посоветовал бы еше добавить const auto_ptr, чтобы избежать возможных проблем с утечками памяти. А для какой задачи это тебе нужно. В стандартной библиотеке есть специальные контейнеры для булевых величин. |
| Автор: zkv 14.4.2007, 13:29 | ||
один из них как раз и есть vector<bool> плохо воспринимается |
| Автор: dizzy1984 14.4.2007, 13:55 | ||
Зато удобно используется. Ну используй typedef.
А точно, специализация. Второй это bitset. |
| Автор: Fazil6 14.4.2007, 14:03 | ||
на самом деле vector<bool> - плохо. Нужно избегать vector<bool>. Это не контейнер STL и он не содержит bool.... В требованиях стандарта говорится, что если v контейнер объектов T , с оператором [] , то должно компиллится
но с bool такая конструкция не скомпилится. vector<bool> - это псевдоконтейнер. |
| Автор: Woo 15.4.2007, 00:07 | ||||
| спасибо, меня еще немного напрягает
я думаю наверно лучше всего использовать
|
| Автор: Fazil6 15.4.2007, 00:24 |
а чего не синхрофазотрон? |
| Автор: JackYF 16.4.2007, 16:10 |
Имхо - нафиг. Слишком много граблей будет да и читабельность... действительно... А серьезно говоря, векторов векторов - это не матрица. В матрице все строки одинаковой длины. В векторе векторов - как захочешь, так и будет. Поэтому еще и вопрос о теоретической применимости. По начальному вопросу - кроме громоздкого объявления, проблем не вижу. Можно, как предлагали, сделать typedef разве что. |
| Автор: dizzy1984 16.4.2007, 19:19 |
Обоснуй, пожалуйста. В c++ есть по крайней мере 2 бича - приведение типов и проблемы с памятью (нет автоматической сборки, выход за пределы массива). Существуют даже языки, специально сделанные для устранения этих проблем (ну и для кое-чего другого), например, java. О каких граблях ты говоришь. Если о передачи владельца, то эти проблемы снимает const. Если о читабельности - есть typedef отступы, комментарии. Мне кажется читабельность менее важна чем стабильная работа программы (отсутствие утечек памяти). Или ты имеешь в виду другой smart pointer вместо этого. Я слышал уже такое мнение и мне интересны его причины. |
| Автор: JackYF 16.4.2007, 21:27 |
Ну, во-первых, если мне понадобятся смарт-поинтеры, то я первую очередь посмотрю на boost::shared_ptr. Про грабли с std::auto_ptr - вот не вспомню сейчас, где и у кого читал, но использование std::auto_ptr чревато очень многими граблями. Я тогда прочитал про эти грабли и для себя поставил галочку - "да, грабли опасные, auto_ptr "ф топку". Например, передача такого ptr в функцию. И как раз const эти проблемы не снимает. Их снимает частично const&. Да и то там... Но это далеко не все. Если как-нибудь пороюсь, то найду дли-и-инный список, почему потенциально плохо юзать std::auto_ptr. Сейчас уже не вспомню все грабли. Добавлено через 1 минуту и 39 секунд Да, кстати, насчет typedef... А приведи-ка пример, как ты его применишь в данном случае. |
| Автор: dizzy1984 17.4.2007, 06:04 | ||
Это и не понадобится, stl контейнеры сами работают с памятью, auto_ptr там не причем. auto_ptr p1,p2; выражение p1=p2 приводит к модификации правой части, в этом и выражается специфика. здесь работает механизм передачи владельца, он призван ограничить количество указателей на 1н объект. Когда такое поведение нежелательно (с трудом представляю себе когда оно может быть желательно) ставят модификатор const. При передаче в функцию в ее сигнатуре объявляют как const &. Другими словами применение const auto_ptr при объявлении указателей на объект и const auto_ptr & при объявлении в функции должно гарантировать отстствие любых "граблей".
Нууу, если твоя программа работает в 40% ситуаций, сопровождать ее будет сложнее, чем, скажем, покопаться в не столько самопонятном коде раз в месяц. JackYF, извини, но в твоем ответе нет ни одной причины почему не стоит его применять. Про boost::shared_ptr ничего не скажу, потому что этой библиотекой не пользовался. ну на счет typedef'а. что-то он слишком ного внимания получает typdef std::auto_ptr<ClassA> CLASSAAUTOPTR; CLASSAAUTOPTR ptr(new ClassA); |
| Автор: Daevaorn 17.4.2007, 07:06 | ||
но auto_ptr нельзя положить в контейнер. |
| Автор: Fazil6 17.4.2007, 12:05 | ||
ага... опять 25... Кто Вам сказал, что правильность работы программы и читабельность ее - это вещи взаимоисключающие ? Код пишется в первую очередь не для компиллятора, а для человека, который будет читать его |
| Автор: dizzy1984 17.4.2007, 12:23 |
| Я так понимаю он используется для единичных объектов. Какой смысл его класть в контейнер, если там и без него работает автоматическая отчистка памяти. |
| Автор: Fazil6 17.4.2007, 12:29 | ||
да. ты прав. просто нужно более развернуто иногда высказываться, ибо в данном случае немного неправильно поняли к чему относится твой auto_ptr и почему-то решили, что его собираются в векторе хранить |
| Автор: JackYF 17.4.2007, 15:02 | ||||
Мдя. Очень читабельно. И главное, сразу все ясно. А если, например, требуется завернуть шаблонный класс? В шаблонной функции даже typedef не сделаешь. А большими буквами делают разве что макросы. Все, кроме MS. Вот от таких вот LPSZ, HUID и более длинных аббревиатур в uppercase уйти сразу хочется и забыть про такой код. Вот! Человек дело говорит. Ты что, указатели никогда в контейнер STL не ложил? 40% - это не вообще работающая программа.
Я не намерен кого-либо переубеждать. Найду как-нибудь книжку или статью, там, где это по полочкам расписано - в личку или в тему выложу. Для себя я галку "не применять" поставил. Хочешь - пользуйся, на здоровье.
Вот. Эта специфика противоречит естественной специфике указателей. Еще одна грабля, если за этим не следить жестко. Объявили в начале функции два объекта "типа указателя"... А потом в середине присвоили чему-то. Ведь это по идее должен был быть указатель... Вот тут-то грабли и могут вылезть. Так мне легче проследить удаление всех объектов, над которыми я сделал new. Кстати говоря, если я забуду освободить память по указателю, это, конечно, не хорошо, но программа не слетит. А вот в случае неявных граблей с auto_ptr - я не уверен. |
| Автор: dizzy1984 17.4.2007, 17:08 | ||||
| ============================ Святая инквизиция, ведьма и auto_ptr. ============================ Все совпадения с реальными людьми случайны, даже если на то не похоже. Темный зал... По стенам бегают отсветы факелов... Судья : сегодня мы собрались здесь, чтобы судить самую страшную, самую жуткую и злую ведьму. Она совершила то, что многие из нас не могли даже представить... Она лечила детей с помощью auto_ptr. Реплики с мест : не может быть, какой ужас!! Судья : да, дамы и господа, увы это правда. В зал вводят ведьму. Видно сгорбленную фигуру под темным капюшоном. Духовный отец1 : ведьма, признаешь ли ты, что это принадлежит тебе. Протягивает ворох листков. Ведьма : Да, это мои рецепты, по ним я лечила детей. Духовный отец2 берет несколько листков. Духовный отец2 : Что я вижу, тут ты писала названия трав заглавными буквами. Ведьма : Да, так мне легче отличить одни травы от других. Духовный отец2 : Это совершенно нечитабельно, ничего не ясно. А как же вы запишете можжевельник, сухой яр и корень мондрагоры? Ведьма : Точно так же, просто мне потребуется больше букв. Духовный отец1 : Чушь! И ты это знаешь, так поступали только давным-давно святые отцы-миссионеры в Ватикане, но уже давно это запрещено под страхом смертной казни. Каждый раз как я вижу такой рецепт мне сразу хочется уйти и забыть про него. Судья : Вы понимаете, что ваши рецепты сложно прочитать? Что вы скажете в свое оправдание? Ведьма : Но ведь я лечила детей и ни один не умер. Судья : Мы здесь говорим не о здоровье детей, мы должны в первую очередь думать о беспорочности нашего ремесла, ремесла лекарей. Если ребенок умер - на то воля господа. Пути его неисповедимы. Встает женщина в кокшнике и кричит со злобой : auto_ptr даже нельзя положить в контейнер. Судья : Вот! Дело говорит верная сестра господа нашего. Ты что, мерзкая ведьма указатели никогда в контейнер STL не ложила? Ведьма : Нет я всегда обходилась обычными объектами. Скажите, чем плох auto_prt? В чем я виновата? Судья : Я не намерен тебе что-либо объяснять. Я хорошо знаю святое писание и там сказано что применять можно только boost::shared_ptr, особенно, когда лечишь детей. Я могу достать его(св. писание) в любой момент, только надо найти нужную полку. Духовный отец1 громко читает один из листков ведьмы: выражение p1=p2 приводит к модификации правой части, в этом и выражается специфика... У судьи наливается краской лицо. Судья : Вот! Вот! Это противоречит самому естеству человеческому, самой сути указателей! Это большая проблема... Ведьма : в рецепте чуть ниже написано, что это поведение снимается применением модификатора const. Судья не обращает внимание на ведьму и продолжает : за ней надо четко следить. Судья постепенно приходит в себя, взгляд его становится осмысленным. Он смотрит на ведьму. Судья : даже если я забуду освободить память по указателю, это, конечно, не хорошо, но ребенок выздоровеет. Конечно, если он часто будет применять зелье, то потеряет руку, может даже обе, но будет продолжать жить. А вот в случае с auto_ptr - я не уверен. Духовный отец1 : Кто за высшую меру наказания - сожжение на костре. Все присутствующие в зале поднимают руки. Духовный отец1 : Единогласно! Стража! Увести ее. 2 Рослых стражника утаскивают сопротивляющуюся ведьму. Если серьезно.
Я уже говорил модификатор const решит эту проблему на этапе компиляции.
Я думаю на форуме лучше оперировать фактами и переубеждать чем просто высказывать неизвестно на чем основанные мнения. А вот тут я ошибся, раз это не макрос - регистр не должен быть строчным. Не бойся макросов, обоснованные макросы могут только упрощать. Fazil6, мы говорим об одном и том же разными словами. |
| Автор: Earnest 17.4.2007, 17:30 | ||
dizzy1984, смешно, но неправильно.
Только в твоем коде. А в коде стандартной библиотеки? Просто не скомпилируется. Например, создаем вектор из нескольких авто-птэров. Потом добавляем еще один. И допустим, это требует перераспределения памяти. Что получится в итоге? А как повезет. Но совершенно не то, на что ты расчитываешь. Это если бы скомпилировалось. Но не должно, и слава богу. Кстати, с "просто" указателями, конечно, скомпилируется. Но вектор перестанет быть полноценным вектором (если все указатели динамические и они же являются владельцами выделенной памяти). В смысле, не все операции будут работать. Да, конечно, можно любой pop или resize сопровождать оператором delete. Но угадай, что получится, если скажем вызвать стандартный алгоритм std::remove_if? Отработает, конечно, но в результате останется выделенная память, на которую больше ничего не указывает. И так со многими алгоритмами. STL предполагает, что объекты в контейнерах имеют корректную семантику копирования и присваивания. Короче, это я к тому, что не надо микроскопом гвозди. Контейнеры\алгоритмы для того и созданы, чтобы не думать о деталях. Чтобы повышать уровень абстракции вашего кода, а не засорять его всякой ерундой вроде удаления указателей при чистке вектора. Указатели, конечно, тоже можно, но только если владельцем их памяти является кто-то еще. |
| Автор: Daevaorn 17.4.2007, 17:30 | ||
нет, проблему решает boost::scoped_ptr, у которого семантика копирования запрещена. Все махинации с std::auto_ptr потенциальные грабли. О чем тебе JackYF уже давно пытается сказать. |
| Автор: JackYF 17.4.2007, 17:42 | ||
А вот тут поподробнее. Использовал где-то в своих кодах std::auto_ptr? В функциях длиннее 10-12 строк?
А тут ребенок ничего не потеряет. За ним просто останется неубранный мусор местами, который уберет не сам ребенок, а уборщица в конце дня. Ага. Ведь к объективной реальности по затрагиваемому вопросу данная повесть имеет мало отношения |
| Автор: dizzy1984 17.4.2007, 18:51 | ||||||||||||||||||||||||||
| Ну что ж очень приятно, что тема привлекла столько внимания. Как все таки иногда бывает полезно рассказать совершенно не относящуюся к теме беседы историю. Напомню, что основной вопрос который здесь обсуждается - можно ли так построить работу с классом auto_ptr, чтобы не было мистических "потенциальных граблей", про которые все слышали, но никто не сталкивался. Что неправильно - не согласен. Правильно. Буду приводить цитаты из книжки C++ Standart Library, The: A Tutorial and Reference.
Абсолютно не понял. auto_ptr не был спроектирован для того чтобы его клали в stl контейнер. Это задумано изначально.
Поэтому и рассуждать про это бессмысленно. Вижу вы сами это понимаете. Далее вы, по-видимому, перечисляете варианты того, как можно положить в контейнер указатель и выделять с его помощью память... ну вы и сами приходите к тому, что это никогда не нужно.
Тезисы. auto_ptr не нужно класть в контейнер. В контейнерные классы вообще никогда не нужно класть указатели, т.к контейнеры сами управляют распределением памяти и на это даже можно повлиять.
Ни JackYF, ни ты не правы. Очередная цитата из книжки
Автор сам говорит, что auto_ptr без const применять нельзя. Конечно, жутковато, но это stl.
Я использую их в качестве полей классов. Это, похоже, единственное применение auto_ptr Защитная цитата
Т.е - auto_ptr есть ни что иное как панацея от проблем с динамической памятью для поля класса в c++. Незащищенный вариант
Защищенный вариант
И возможно здесь и кроется разгадка всего нашего спора. Возможно, вы думали о каком-то другом применении auto_ptr? По-другому я его применять не собираюсь. Если применять const auto_ptr для члена класса, который не является массивом, то да память освободится в любом случае.
Несомненно, ведь я такой фантазер Чисто для очистки совести приведу остальные misusing для auto_ptr
|
| Автор: Daevaorn 17.4.2007, 19:04 | ||||||
dizzy1984, говорят, что "краткость сестра таланта". Не слышал об этом?
Я плакал.
ааа. скорую мне. Меня бы уволили за такое применение std::auto_ptr
ааа.спосите мой мозг. Надо иногда и своей головой думать, а не только книжки в форум перепечатывать. |
| Автор: JackYF 17.4.2007, 19:08 | ||||
operator=, например... выдержка.
Твои действия в этом случае с помощью std::auto_ptr? |
| Автор: Earnest 17.4.2007, 19:24 | ||||
| Хм, мне показалось, что речь с самого начала шла об использовании auto_ptr в контейнерах... Особенно в твоей леденящей истории:
Но если нет, то и ладно. А сам по себе auto_ptr, использованный правильным образом (т.е. как отдельная автоматическая переменная), опасен разве что граблями с присваиванием... о чем уже писали. Однако, если следовать Мерфи, на валяющиеся грабли рано или поздно кто-нибудь наступит.
Да уж. Не только не единственное, но и не особо удачное применение. В общем, нормальный указатель с эксклюзивным владением (бустовский или самописный), не имеющий конструктора копирования, абсолютно заменяет auto_ptr там, где auto_ptr безопасен, и не дает себя использовать там, где это опасно. Короче, единственное оправдание в его использовании - это то, что в stl другого нет. Но это не оправдание. И, кстати, насчет правильности кода. Кроме "правильный" или "неправильный" код еще может быть "вонючим". Вот auto_ptr именно такой. Работает вроде. Но попахивает... |
| Автор: dizzy1984 17.4.2007, 19:57 | ||
Какое(ие) применение будет удачнее? Я так понял, что почва использования неконстантного auto_ptr очень шаткая из-за его механизма передачи владельца. Поэтому я бы использовал другой умный указатель для твоего примера |
| Автор: JackYF 17.4.2007, 20:52 | ||
О чем и речь. Не раз указатели в полях моих классов ведут себя именно таким образом. Именно так я писал копирования (там, где это было быстро и удобно), и всего лишь один-единственный раз не забывал про деструктор. Прописать там одну строчку - не проблема, имхо. Это не стоит выделения pointer'ов в smart-pointer. Это из пушки по воробьям. Здесь - даже не знаю. Мое имхо по этому вопросу - я обхожусь без них, а вообще - разве что в локальных функциях, там больше риск забыть удалить |
| Автор: Earnest 17.4.2007, 21:32 | ||
Ты сильно не прав. Вот представь. Копируешь ты объект с обычным указателем (даже не замечая, скажем, возвращая из функции по значению). И кто будет уничтожать твой пойнер? Правильно, тот кто первым разрушится. А второй объект будет обращаться к мусору. Вот радость-то. С другой стороны, если ты используешь smart-pointer, компилятор просто не сможет сгенерировать копи-конструктор сам - обругается. Поэтому, если обяъект не должен копироваться - smart-pointer самое то. Только лучше бы явно сделать класс non_copyble. А если хочешь-таки копировать - не вопрос: либо пиши сам глубокий конструктор копирования, либо используй пойнтер с подсчетом ссылок. ИМХО, издержки (написание кода или ознакомление с готовым классом) на использование разнообразных смарт-пойнтеров окупаются всегда. |
| Автор: dizzy1984 17.4.2007, 21:40 | ||
Но ведь так не всегда. У меня нет нужды в операторе =, почему бы мне не использовать auto_ptr. Хотя для более общего случая можно поискать и более крутых смартпоинтеров. Есть еще один момент во всей этой истории... Динамически выделенная память не освобожается при срабатывании исключений. Применимо для классов это значит, что есть вероятность ситуации, когда после выделения памяти под поля в конструкторе срабатывает исключение. деструкторы вызываются для уже созданных объектов, после чего происходит разворачивание стека. Разворачиваясь стек давит автоматические переменные. Если такая автоматическая переменная будет смартпоинтером, то она может в своем деструкторе освободить память под объект. Вообщем-то для этого он и создавался. Не против забывчивых людей, но для защиты от исключений в конструкторах и функциях. В функции история такая же. Если в ней динамически выделяется объект, есть возможность порождения исключения, значит есть вероятность утечки память, т.к сработав, исключение обойдет участок кода, где человек с хорошей памятью Я, конечно, может быть пароноик. Возможно, в mfc не так уж много ситуаций генерации исключений. Но не лучше ли перестраховаться, если это не трудно. |
| Автор: JackYF 18.4.2007, 13:17 | ||||
Согласен. Но эта проблема столько раз поднималась в книжках... поэтому если класс все-таки copyable, то я, когда пишу конструкторы к нему, автоматом пишу и конструктор копий + operator=. Привычка уже выработалась, что ли. Опять-таки имхо, но обычные указатели в классах я храню крайне редко. Гораздо чаще я храню там обычные/не очень массивы (объектами, со всеми преимуществами наличия деструкторов и т.д.). Обычные указатели у меня хранятся в самых базовых и/или абстрактных классах, которые все-таки пишутся сосредоточенно и отлаживаются тоже жестко. Стоит ли применять там smart-pointer'ы? Просто это или тот же класс массива, или другой тип умного указателя. В общем, если не из пушки, то из базуки. у меня в 95% оператор= есть.
Этот момент есть. Тут согласен. |
| Автор: Earnest 19.4.2007, 07:54 | ||
Это хорошо, что выработалась. А если указатель добавляется в класс не сразу, а в процессе поддержки, и не тобой, а тем, у кого еще не выработалась? А если класс не copyable? А ты ошибешься? Компилятор для класса с указателям сгенерирует коструктор копирования запросто. Конечно, можно заранее принимать для этого меры, т.е. сразу объявляетть класс как Non-copyable, и это правильно. Но это меры того же порядка, как использование смарт-пойнтеров вместо указателей, что ты считаешь "пушкой по воробьям". А это вовсе не пушка, а просто чуть модифицированная рогатка: накладных расходов практически никаких (или вовсе никаких, если нет подсчета ссылок), все инлайн. Тебя пугает код смарт-пойнтера? Так в шаблонах длина написанного кода никак не влияет на размер результирующего exe. У одного из гуру программирования я встречала фразу: самый безопасный код - этот тот, которого нет. Отсюда следует вывод: все, что можно поручить компилятору, пусть он и делает. Т.е. самые лучшие деструкторы - это пустые (в твоем коде, разумеется). Захват ресурса == инициализация. И т.д. |
| Автор: JackYF 19.4.2007, 15:56 | ||||
Хорошая фраза. Да нет, не очень
Ну, тогда не фарт. Согласен. Да. Доводов против не имею. |