![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| En_t_end |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2074 Регистрация: 4.12.2004 Репутация: 1 Всего: 20 |
В неком классе на основе некого массива есть такой оператор:
Испытываю проблемы при компиляции... ругается на вот такое:
Говорит, что значение может присвоенно быть только переменной, это я и без него знаю(lvalue must be left!) Вот только непонятно почему я не могу присвоить SomeMemb находящемуся в некоторой структуре SomeType значение SomeValue, как надо обращаться в подобных случаях ? |
||||
|
|||||
| srd |
|
|||
![]() Нереварин ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 951 Регистрация: 30.8.2003 Где: Владивосток Репутация: 27 Всего: 49 |
У тебя перегруженный оператор возвращает копию, а должен возвращать ссылку.
-------------------- Не смей читать мою подпись!!! |
|||
|
||||
| En_t_end |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2074 Регистрация: 4.12.2004 Репутация: 1 Всего: 20 |
Точно!!!
Вот она ошибка... Добавлено @ 11:22 somestor_cl[someindex]->SomeMemb - это во вторых, а SomeType operator[](unsigned long index){return somestor[index]}; меняем на SomeType* operator[](unsigned long index){return &somestor[index]}; |
|||
|
||||
| srd |
|
|||
![]() Нереварин ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 951 Регистрация: 30.8.2003 Где: Владивосток Репутация: 27 Всего: 49 |
А может вместо
SomeType* operator[](unsigned long index){return &somestor[index]}; лучше будет SomeType& operator[](unsigned long index){return somestor[index]}; и писать потом somestor_cl[someindex].SomeMemb -------------------- Не смей читать мою подпись!!! |
|||
|
||||
| En_t_end |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2074 Регистрация: 4.12.2004 Репутация: 1 Всего: 20 |
srd
У меня к ссылкам какое-то врожденное недоверие... Добавлено @ 15:20 по мне так лучше возвращать указатель( это из области наглядности, которую мы кстати уже в одной теме обсуждали) |
|||
|
||||
| srd |
|
|||
![]() Нереварин ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 951 Регистрация: 30.8.2003 Где: Владивосток Репутация: 27 Всего: 49 |
В противном случае ты нарушаешь семантику оператора []. Оператор [], возвращающий указатель на объект вместо ссылки, это как оператор +, который вместо сложения операндов их перемножает. -------------------- Не смей читать мою подпись!!! |
|||
|
||||
| nikitao |
|
|||
![]() Кот-программист ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1206 Регистрация: 30.8.2005 Где: Спб Репутация: 1 Всего: 26 |
ПОЧЕМУ????(ИМХО) ЭТО ОЧЕНЬ ОЧЕНЬ УДОБНЫЙ ИНСТРУМЕНТ. -------------------- Жизнь - печальная штука. |
|||
|
||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
И еще в пару к нему SomeType operator[](unsigned long index) const {return somestor[index]}; Чтобы совсем было правильно. Это чтобы с константными объектами правильно работалось. И брось на тему ссылок заморачиваться. -------------------- ... |
|||
|
||||
| maxim1000 |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 17 Всего: 110 |
а почему не так: const SomeType &operator[](unsigned long index) const {return somestor[index]}; ? просто я представил ситуацию: const SomeType *f(const SomeClass &qqq) { return &qqq[1]; } void g(const SomeClass &qqq) { print(*f(qqq)); } в данном случае будет нехорошо, т.к. f вернет указатель на временный объект, который уничтожится после выхода и распечатается мусор... -------------------- qqq |
|||
|
||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
Можно и так (если объект большой и его не очень хочется возвращать по значению).
А вот твой пример - это не аргумент. Это в равной степени относится к любым стандартным контейнерам STL. И вообще к любой функции, которая возвращает значение, а не ссылку. Пример:
Ну и ? Такие функции просто не надо писать. Не надо забывать, что C++ дает возможность писать безопасный код, а вовсе не гарантирует безопасность - как бы программист не выделывался. -------------------- ... |
|||
|
||||
| srd |
|
|||
![]() Нереварин ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 951 Регистрация: 30.8.2003 Где: Владивосток Репутация: 27 Всего: 49 |
Я так полагаю, что maxim1000 имел в виду другую проблему:
Кошерные оператор [] должен возвращать ссылку, а константынй оператор [] - константную ссылку. -------------------- Не смей читать мою подпись!!! |
|||
|
||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
Не согласна, это пример из той же серии.
Ведь в зависимости от реализации, объект может просто не существовать в памяти, а скажем вычисляться, или еще как-то хитро выковыриваться. Константный опаратор [] должен вызывать нечто, что может быть rvalue, и не обязано иметь адрес. А "кошерный" код не должен закладываться на реализацию. Сегодня я использую массив в памяти (внутри класса), а завтра захочу усложнить реализацию, и все буду хранить, ну не знаю, на соседней машине. Попробуй скажи, что не имею права! И полетит твой код ко всем чертям. Еще раз повторяю - такие функции просто нельз я писать. -------------------- ... |
|||
|
||||
| maxim1000 |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 17 Всего: 110 |
вот с чем я тут полностью соглашусь, так это с тем, что и та, и та форма может оказаться правильным решением в конкретной ситуации
просто я стараюсь придерживаться того, чтобы при переопределении какого бы то ни было оператора его семантика менялась как можно меньше, и если информации о ситуации недостаточно, я придерживаюсь этого принципа а взятие адреса поддреживается стандартным [] что касается примера... предположим, что программист написал этот код без использования const он чудесно скомпилится и даже будет работать потом этот программист читает какую-нибудь статью, которая говорит "используйте const везде, где это вам не мешает" и ставит const... и получает ошибку при компиляции и несмотря на то, что действительно виноват программист, а не автор класса, мне это кажется не очень хорошо (опять же - просто кажется)... что касается вычислимых полей, то даже их неконстантная версия [] не должна возвращать ссылку... -------------------- qqq |
|||
|
||||
| LPBOY |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 228 Регистрация: 12.7.2005 Репутация: 20 Всего: 20 |
Угу. Кроме того зачем нужны лишние расходы на копирование, если можно их избежать? P.S. Хотя спор о ерунде, ИМХО. --------------------
Каждый человек по-своему прав, а по-моему нет... |
|||
|
||||
| srd |
|
|||
![]() Нереварин ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 951 Регистрация: 30.8.2003 Где: Владивосток Репутация: 27 Всего: 49 |
Ну что ж, оператор[], качающий данные с соседней машины - это суровый аргумент
-------------------- Не смей читать мою подпись!!! |
|||
|
||||
| maxim1000 |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 17 Всего: 110 |
не совсем... я думал привести этот аргумент... тут есть одна тонкость: если поле вычисляемое, в любом случае надо создавать объект, который будет хранить результаты в случае возврата ссылки единственный способ - создать объект в куче и вернуть ссылку на него (потому как возвращать ссылку на временный объект - просто ужасно), это приведет к путаннице с вопросом "кто и когда должен его удалять, чтобы не было утечки памяти" в случае вычислимых полей вариант без ссылки действительно лучше... -------------------- qqq |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 3 Всего: 106 |
пожалуй многие согласятся с тем, что кучу перегруженных operator [] лучше заменить на пару:
operator SomeType*(void) и operator const SomeType*(void) просто подумайте, на сколько это удобно somestor_cl[someindex] - работает (somestor_cl + someindex)->SomeField - работает и не надо лишнее писать:return somestor[index] Ещё один плюс (на мой взгляд - наиболее значимый): в операторе [] - шаблонный класс не сможет выдать подсказку после ".", или "->" при нажатии Ctrl+Space, а в SomeType*(void) - сможет -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| LPBOY |
|
||||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 228 Регистрация: 12.7.2005 Репутация: 20 Всего: 20 |
Я не очень понял что такое "вычислимые поля", а также почему "в любом случае надо создавать объект". Но проблемы никакой тут нет и копировать ничего не надо. И вообще что ты имел в виду Добавлено @ 17:35
Я не соглашусь. В этом случае класс SomeType будет участвовать и в других контекстах как указатель. Нет причин отказываться от оператора[]. --------------------
Каждый человек по-своему прав, а по-моему нет... |
||||
|
|||||
| maxim1000 |
|
||||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 17 Всего: 110 |
и что они будут возвращать? для этого придется гарантировать, что все объекты контейнера идут по порядку, а это - далеко не самый частый случай...
сможет...(тестировал в Builder'е, VC под рукой нету)
пример: пусть мы сделали класс векторов, у которых координаты образуют арифметическую прогрессию (при создании указывается начало и шаг), при этом нам очень хотелось бы, чтобы была возможность писать cout<<v[6]; все бы хорошо, но хранить все эти значения просто расточительно для такого вектора длиной 100 нужно будет 100 чисел, хотя можно было бы обойтись двумя (начальным элементом и шагом) тогда можно написать такой оператор:
в этом случае ссылку возвращать попросту не на что... -------------------- qqq |
||||||||
|
|||||||||
| GremlinProg |
|
||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 3 Всего: 106 |
поясни, не понял Добавлено @ 17:46
Вот и зря, что нету, "а какие же в билдере богатые шаблоны..." просто так, к слову. -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||
|
|||||||
| LPBOY |
|
||||||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 228 Регистрация: 12.7.2005 Репутация: 20 Всего: 20 |
Ну ты загнул
Во-первых ты наверное имел в виду не оператор преобразования к SomeType* , а к типу указателя на встроенный тип.
Это я имел в виду что теперь объекты SomeType можно - разыменовывать - складывать с целыми числами - осуществлять неявное преобразование к bool и void* - передавать в функцию, если на самом деле она ждет указатель и т.д. Эти побочные эффекты явно ни к чему. Это сообщение отредактировал(а) LPBOY - 14.10.2005, 17:55 --------------------
Каждый человек по-своему прав, а по-моему нет... |
||||||
|
|||||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 3 Всего: 106 |
Честно говоря, класс, который в операторе [] возвращает элемент, по арифметической прогрессии мне не вселил бы уверенности, т.к. его логика непонятна. Оператор [] изначально подразумевает ВЕКТОР. Не вижу логики, зачем прятать элементарную формулу в контейнере, когда можно( и нужно! ) повесить независимый класс на индекс. Повторюсь, не вижу логики, мы ведь должны облегчить читаемость кода, а не скомпоновать всё и вся
-------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| srd |
|
|||
![]() Нереварин ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 951 Регистрация: 30.8.2003 Где: Владивосток Репутация: 27 Всего: 49 |
А если ещё и не увлекаться explicit конструкторами, то поведение программы может стать непредсказуемым. -------------------- Не смей читать мою подпись!!! |
|||
|
||||
| GremlinProg |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 3 Всего: 106 |
LPBOY
похоже, ты не понял
пример:
это я и имел ввиду! здесь не создаются промежуточные экземпляры, оператор T* ведёт себя, как встроенный оператор [] Это сообщение отредактировал(а) GremlinProg - 14.10.2005, 18:00 -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
| maxim1000 |
|
||||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 17 Всего: 110 |
это был всего лишь пример на вычислимые поля
пример: частоиспользуемый страндартный контейнер map или, например, динамический список с добавленной операцией доступа по номеру...
сильно подозреваю, что и в VC сможет operator[] не очень-то от функции отличается, так что сложность определения, что выдавать при нажатии "." после значения известного типа (а тип известен) не сильно зависит от того, оператор там стоит или функция... Добавлено @ 18:03
я тоже это имел в виду, когда писал, что лучше делать ссылки и там, и там но пример вычислимых полей был приведен, и поспорить, что в этом случае возвращать значение лучше, сложно... а вопрос, насколько часто такое встречается... всякое бывает -------------------- qqq |
||||||||
|
|||||||||
| LPBOY |
|
||||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 228 Регистрация: 12.7.2005 Репутация: 20 Всего: 20 |
Я понял. Я просто говорю про побочные эффекты... Чем тебе оператор [] не нравится?
Просто вариант с оператором преобразования не такой чистый и понятный как с оператором []. --------------------
Каждый человек по-своему прав, а по-моему нет... |
||||
|
|||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 3 Всего: 106 |
хорошо, что есть map, а то я и не знал. Вот только нотификации о изменении базы вектора я что-то там не наблюдаю. А ведь это огромный минус и как быть. Понимаешь, не всё можно найти в stl и ей подобных, иногда нужно и свои мозги включать!
-------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| maxim1000 |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 17 Всего: 110 |
почему непонятна? просто этот класс представляет собой вектора с указанным ограничением никто не запрещает хранить их в классическом виде, но "маскирование" оператора [] позволяет: 1. сократить затраты памяти 2. не заставлять пользователей класса менять свой код или, например, иногда встречаются разреженные вектора - про которые мы знаем, что там будет много нулей опять же можно просто хранить ненулевые поля в списке, а про остальные говорить, что они равны нулю... такие вектора можно использовать при построении разреженных матриц, а это - вообще отдельная тема в численных методах... Добавлено @ 18:08
честно говоря, не понял, что имелось в виду... -------------------- qqq |
||||
|
|||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 3 Всего: 106 |
class X{ public: X(int){} }; class Y{ public: X operator[](unsigned id){ if(id < length){ X null; return null } return lpvector[id]; } }; допустим, Y - шаблон, а X - параметр шаблона, как в предыдущем варианте, что будет? -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| LPBOY |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 228 Регистрация: 12.7.2005 Репутация: 20 Всего: 20 |
Просвети... --------------------
Каждый человек по-своему прав, а по-моему нет... |
|||
|
||||
| GremlinProg |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 3 Всего: 106 |
при вызове realloc(lpmem,newsize), lpmem может поменять базу, в этом случае, если в программе, где-то хранятся указатели на элементы lpmem, их нужно обновить в соответствии с новой базой, иначе при обращении к любому из таких указателей произойдёт наша любимая "Access violation" нотификация(notification) - это шаблонный или виртуальный метод, который вызывается как раз в момет смены базы. Добавлено @ 18:24
В этом случае код просто не откомпилится, пока ты не опишешь в классе X конструктор по-молчанию. Я это к тому, что оператор TYPE [] накладывает свои ограничения на TYPE. В данном случае это очевидно. Не всегда можно описать конструктор по-умолчанию. Если в классе есть поля типа TYPE&, то их надо в любом случае инициировать. Если в .NET можно написать так: *(TYPE*)NULL, то в C++ 6.0 этого сделать нельзя, т.к. компилятор сразу подставляет в такие места что-то вроде mov eax,[ecx], где ecx = 0 (Надеюсь идея ясна) Это сообщение отредактировал(а) GremlinProg - 14.10.2005, 18:42 -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
| LPBOY |
|
||||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 228 Регистрация: 12.7.2005 Репутация: 20 Всего: 20 |
Кто виноват если ты не определил конструктор по умолчанию для Х, а потом пишешь:
Если правильно написать оператор[], то и проблем не будет. --------------------
Каждый человек по-своему прав, а по-моему нет... |
||||
|
|||||
| srd |
|
|||
![]() Нереварин ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 951 Регистрация: 30.8.2003 Где: Владивосток Репутация: 27 Всего: 49 |
Полагаю, что вместо возвращения null оператор[] должен в случае ошибки бросить исключение, либо вообще не делать никаких проверок. Семантика у него такая - не делать проверок
-------------------- Не смей читать мою подпись!!! |
|||
|
||||
| GremlinProg |
|
||||||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 3 Всего: 106 |
Никто, просто это говорит об ограниченности класса, а если тебе нельзя по другому(см. предыд. ответ) тоты просто пишешь свой класс, вместо встроенного. Вот они, частные случаи. Добавлено @ 18:49
Правильно, тогда чем отличается [] от TYPE Упс, совсем из головы вылетело: меня собственно заинтересовал момент перегрузки TYPE&operator[] и const TYPE&operator[]. Допустим есть функция:
и
Если вызвать её так:
то компилятор сообщит об ошибке "ambrigous access", т.е. непонятно какой оператор вызвать c const TYPE&, или TYPE&. Так вот в случае с operator TYPE*(), этой ошибки никогда не произойдёт, я специально этот момент проверял (в своё время очень нужно было). Это сообщение отредактировал(а) GremlinProg - 14.10.2005, 19:13 -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||||||
|
|||||||||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
По-моему ты куда-то не туда загнул.
Сравнивать оператор приведения и извлечения по индексу бессмысленно, это совершенно разные операции. Оператор приведения типа многие гуру (в частности, Майерс) считают опасным и рекомендуют использовать как можно реже. Т.е. только в тех случаях, когда его семантика очевидна. Например, в классах-оболочках. А заменять ими оператор доступа к элементу контейнера - полная ересь. -------------------- ... |
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |