RXL
Технический
Администратор
Offline
Пол:
|
|
« : 11-12-2010 22:33 » |
|
Пример: class A { public: int x; int y; A(int x, int y) : x(x), y(y) { }; };
typedef std::map<int, A*> ACollection;
class B { ACollection list; public: const A & a(int index) const; const A * a(int index) const; };
const A & B::a(int index) const { return *(list[index]); }
const A * B::a(int index) const { return list[index]; } Какие тут достоинства и недостатки у методов B::a? // B b;
var = b.a(1).x; var += b.a(1).y;
ptr = b.a(1); var = ptr->x; var += ptr->y; С одной стороны, работа с ссылкой как-то проще. С другой, поиск в map для каждого доступа будет накладен. И с одной переменной (как с указателем) не поработаешь (даже если убрать const): A &ref = b.a(1); ref = b.a(2); // присвоение b.a(1) = b.a(2) А указатель можно засунуть в delete... Или все же можно от такого предохраниться?
|
|
« Последнее редактирование: 13-12-2010 04:31 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #1 : 11-12-2010 22:39 » |
|
При получении извне, указатель всегда нужно проверять на NULL.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #2 : 12-12-2010 08:47 » |
|
а по мне, так между ссылками и указателями нет разницы. Всё, что делается с одним, можно сделать и с другим
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #3 : 12-12-2010 09:43 » |
|
Леш, ты несколько заблуждаешься. Ссылка намного более капризна.
Недостатки ссылок: 1. Нельзя объявить ссылку заранее - она требует инициализации при создании. 2. Нельзя изменить ссылку, чтобы она ссылалась на другой объект. 3. Случайное присвоение ссылке может испортить объект, на который она ссылается (если объект не const).
Недостатки указателей: 1. Требует разыменования (*) или более длинной записи (->). 2. Чередования указателей, объектов и ссылок могут запутать (a->b().c.d->e()->f = 1;). 3. Указатель можно ненароком удалить (передать в delete), даже если это не требуется.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #4 : 12-12-2010 13:56 » |
|
Ссылки оказались удобны для хранения внутри объекта динамических объектов, передаваемых в параметрах конструктору и уничтожаемых одновременно с объектом-носителем: нет нужды вызывать delete (не запутаешься) и гарантированная инициализация, а также нельзя передать в конструктор NULL-указатель (гарантированный Segmentation fault). #include <stdio.h>
class TestData { public: int x;
TestData() { puts("_ create TestData"); }; ~TestData() { puts("_ destroy TestData"); }; };
class Test { TestData &data; public: Test(TestData &initData) : data(initData) { puts("_ create Test"); }; ~Test() { puts("_ destroy Test"); }; int x() { return data.x; }; };
int main(void) { TestData *td = new TestData(); Test *t;
td->x = 10; t = new Test(*td);
printf("Test: %d\n", t->x());
delete t; return 0; } _ create TestData _ create Test Test: 10 _ destroy Test _ destroy TestData
Добавлено через 59 минут и 59 секунд:Ошибочка вышла... Фига с два он вызывает деструктор Т.е. для ссылок деструктор не вызывается. Жаль. Разве что добавить в ~Test код: delete &data;
|
|
« Последнее редактирование: 12-12-2010 15:02 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #5 : 12-12-2010 19:08 » |
|
Леш, ты несколько заблуждаешься. Ссылка намного более капризна.
Недостатки ссылок: Недостатки указателей:
это не недостатки, а следствие их смысла (который поддерживается компилятором): указатель - хранилище адреса, а ссылка - синоним (но внутри - такое же хранилище адреса). Ошибочка вышла... Фига с два он вызывает деструктор Т.е. для ссылок деструктор не вызывается. Жаль. Разве что добавить в ~Test код: delete &data;
это потому, что я не заблуждаюсь
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #6 : 12-12-2010 20:19 » |
|
Это я пытаюсь внедрить модели в насквозь запроцедуренный код — его стало мучительно поддерживать и изменять. Приходится заново изучать давно забытое
|
|
« Последнее редактирование: 12-12-2010 20:21 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Антон (LogRus)
|
|
« Ответ #7 : 13-12-2010 04:20 » |
|
С одной стороны, работа с ссылкой как-то проще. С другой, поиск в map для каждого доступа будет накладен. И с одной переменной (как с указателем) не поработаешь (даже если убрать const): A &ref = b.a(1); ref = b.a(2); // присвоение b.a(1) = b.a(2) не понял тебя, ни про map, не про присвоить про недостатки ссылок не согласен, это своиства, дающие некоторые бонусы у Брюса Эллеля насколько я помню хорошо про это расписано и у Скотта Мейерса указатели на внетренние данные стараюсь не возвращать, за исключением случаев, когда указатель более уместен народ рекомендует не использовать ссылки при передаче параметров, если внутри меняется значение хранимое по ссылке, т.к. это делает не очевидным поведение функции http://easy-coding.blogspot.com/2010/11/blog-post.htmlну это такой вопрос для холивара я бы сказал, что круче, то или это лично я просто стараюсь выбирать их так, что бы поведение функций было очевидно
|
|
|
Записан
|
Странно всё это....
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #8 : 13-12-2010 04:30 » |
|
Антон, чего не понятного "про map"? Не цитировать де пример в полном объеме const A & B::a(int index) const { return *(list[index]); }
const A * B::a(int index) const { return list[index]; } var = b.a(1).x; var += b.a(1).y; Я про это. Чтобы, используя вариант с возвращаемой ссылкой, доступиться к N свойствам требуется вызвать код N раз. Или делать локальную ссылку: { A &ref = b.a(1); var = ref.x; var += ref.y; } В примере была опечатка - убрал одну звездочку.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Антон (LogRus)
|
|
« Ответ #9 : 13-12-2010 04:55 » |
|
1. тебе и с указателем и без нужно вызывать поиск N раз, для контейнеров не хранящих данные одним блоков в памяти, нельзя применять алгебру указателей 2. ах вот ты о чём, перечитал первый пост и твоё дополнение и наконец догнал в данном конкретном случае, тебе нужны не ссылки и не указатели, тебе нужны итераторы class A { public: int x; int y; A(int x, int y) : x(x), y(y) { }; };
typedef std::map<int, A*> ACollection;
class B { ACollection list; public: typedef ACollection::iterator Iterator; typedef ACollection::const_iterator CIterator; public: CIterator a(int index) const; };
CIterator B::a(int index) const { return list.find(index); }
|
|
|
Записан
|
Странно всё это....
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #10 : 13-12-2010 05:07 » |
|
Какое преимущество это даст?
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #11 : 13-12-2010 08:08 » |
|
Некоторое неудобство использования итераторов: it->second->method();
ptr->method();
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #12 : 13-12-2010 08:11 » |
|
а я вот так делаю, когда много обращений MYTYPE& m=it->second; m.method(); m.method2(); m.method3();
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #13 : 13-12-2010 08:24 » |
|
Леш, тогда проще сразу "const Type &" возвращать...
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #14 : 13-12-2010 08:37 » |
|
да нет разницы. С итератором даже лучше - так как может first тоже понадобиться
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #15 : 13-12-2010 08:38 » |
|
Я для удобства все таки этот индекс храню и в самом объекте.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #16 : 13-12-2010 08:52 » |
|
ну, я тоже, кстати )
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #17 : 13-12-2010 12:24 » |
|
итератору множно делать ++ и -- можно проверить на конец данных при движении в любую сторону можно передавать в стандартные алгоритмы ну и да у итератор мапы не сильно удобный
|
|
|
Записан
|
Странно всё это....
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #18 : 13-12-2010 14:45 » |
|
В том то и дело, что получая нечто по индексу совсем не нужно никуда перемещаться. Видимо лучше все же указатель или ссылку. Вопрос темы возвращается: что лучше использовать для возвращаемого значения?... Думаю, что для монотонности интерфейса лучше ссылку.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #19 : 13-12-2010 14:50 » |
|
Когда возвращаешь указатель, можно вернуть 0, это скажет о невозможности выдачи указателя. А со ссылкой придётся возвращать bool
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #20 : 13-12-2010 14:54 » |
|
Лучше не специальное значение возвращать, а бросить исключение. Иное допускаю только на методах, которые специально проверяют возможность действия. Хотя, если почитать классиков, и тут можно использовать исключения.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #21 : 13-12-2010 15:54 » |
|
эээ, зачем ещё исключения, когда проще проверить на 0 ?
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #22 : 13-12-2010 17:24 » |
|
у меня дурацкий вопрос, если доступ по индексу, то зачем нужен map ?
|
|
|
Записан
|
Странно всё это....
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #23 : 13-12-2010 18:41 » |
|
Так индекс - первый параметр map. Т.е. в объекте хранится коллекция однотипных элементов с уникальными индексами, по которым их выбирают по одному. Также треба выбирать все элементы - на этот случай я завел пару функций, возвращающих пару итераторов.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Антон (LogRus)
|
|
« Ответ #24 : 14-12-2010 04:42 » |
|
Так индекс - первый параметр map. Т.е. в объекте хранится коллекция однотипных элементов с уникальными индексами, по которым их выбирают по одному. Также треба выбирать все элементы - на этот случай я завел пару функций, возвращающих пару итераторов.
Так индекс - первый параметр map. Т.е. в объекте хранится коллекция однотипных элементов с уникальными индексами, по которым их выбирают по одному. Также треба выбирать все элементы - на этот случай я завел пару функций, возвращающих пару итераторов.
map ассоциативный контейнер с временем доступа к элементу O(log n) если у тебе есть все элементы от 1 до N, то тебе map явно не нужен, тебе нужен вектор или deque если набор разреженный, т.е. есть элементы с ключами 1, 2, 5, а 3 и 4 нет, то да тут нужен map если у тебя ключ это число, то лучше посмотреть в строну hash_map Далее, у тебя есть возражения насчёт итереторов указатели не дадут возможность построить диапозон, их нельзя передать в стандартные алгоритмы, в твоём случае по ним можно получить доступ к одному элементу и всё, больше с ними ничего не сделаешь. Если тебе не нравится итератор map из-за его дебильно first/second, то напиши свой итератор, который обладает нужным поведением, сохраняя поведение итератора map, благо это не сложно template <typename TIter = map::iterator> class Iterator { TIter iter_; public: typedef TIter::key_type TKey; typedef TIter::mapped_type TValue; TKey Key() {return iter_->first; } TValue & operator->() { return iter_->second; } // далее опиши всякие ++/--/== если они тебе нужны для работы диапозонов например // будет полезно перегрузить оператор * } если нужно просто получить доступ к элементу, пользуешься как обычным указателем, если нужно вытащить ключ используешь метод Key
|
|
« Последнее редактирование: 14-12-2010 04:47 от Антон (LogRus) »
|
Записан
|
Странно всё это....
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #25 : 14-12-2010 04:49 » |
|
Индексы не 1..N, а уникальные идентификаторы из БД. Соотв., номера произвольные, разреженность произвольная.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
|