Russian Qt Forum
Ноябрь 23, 2024, 20:18 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3   Вниз
  Печать  
Автор Тема: Передача по ссылке или указателю?  (Прочитано 20993 раз)
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #15 : Август 16, 2011, 19:32 »

Здесь об этом немного, но понятно написано
В смысле по-русски?

Насколько я понял, при модификации данных глубокое копирование все равно происходит.
Разумеется. Нельзя же без копирования переданное значение поменять, а оригинал оставить неизменным.

Соль в том что можно передавать по значению и:
1) если не будет изменений, то не будет лишнего копирования данных, т.е. фактически замена константной ссылке;
2) если будет изменение, то само всё копируется (не изменив оригинал) и об этом не нужно задумываться, т.е. фактически замена передачи по значению;
3) и кроме того это потоко-безопасно, то есть мы можем передавать такой класс как аргумент сигнала и неизменные данные дойдут до всех присоединённых слотов, даже если некоторые из них вызываются в других потоках и на момент их активации оригинал передаваемого объекта уже успел измениться или даже удалиться.

Обращу внимание, что потоко-безопасна именно Qt-шная реализация, вообще говоря Implicit Sharing не обязан быть потоко-безопасным.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #16 : Август 16, 2011, 20:33 »

Соль в том что можно передавать по значению и:..
Правильная метода обучения - бить начинающего мокрым веником по заднице за каждую передачу/возврат структуры по значению. А когда научится - разберется с implicit sharing (если захочет). А все эти "вообще нельзя но все-таки можно.." ничего хорошего не приносят.

Да и неясно в плюс тот sharing или в минус - грузить d-> может быть ощутимым, когда-то понадобится STL контейнер и.т.п.

Обращу внимание, что потоко-безопасна именно Qt-шная реализация, вообще говоря Implicit Sharing не обязан быть потоко-безопасным.
Qt реализация безопасна только в том смысле что нитка может делать shared копию данных - и потом ее менять. Но это не значит что 2 или более ниток могут читать/писать одновременно одни и те же данные без синхронизации, поэтому смысла в той безопасности немного.
« Последнее редактирование: Август 16, 2011, 20:45 от Igors » Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #17 : Август 16, 2011, 21:31 »

Правильная метода обучения - бить начинающего мокрым веником по заднице за каждую передачу/возврат структуры по значению. А когда научится - разберется с implicit sharing (если захочет).
Я где-то говорил, что Qt подходит для обучения азам программирования? Шокированный

Да и неясно в плюс тот sharing или в минус - грузить d-> может быть ощутимым, когда-то понадобится STL контейнер и.т.п.
Всё когда-то может пригодиться.
К слову, в gcc std::string, например, тоже copy-on-write, хотя это конечно не контейнер, но всё же часть STL.

Qt реализация безопасна только в том смысле что нитка может делать shared копию данных - и потом ее менять.
Да, я именно об этом и сказал. Выше указанная std::string нам тут безопасность не гарантирует.

Такая концепция классов родилась в Qt4 прежде всего именно ради безопасной передачи в сигналах/слотах без излишнего копирования.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #18 : Август 16, 2011, 22:47 »

Да, я именно об этом и сказал. Выше указанная std::string нам тут безопасность не гарантирует.
Ну это легко обходится, давеча изучали  Улыбающийся

Такая концепция классов родилась в Qt4 прежде всего именно ради безопасной передачи в сигналах/слотах без излишнего копирования.
А в чем эта безопасность, и что выиграли по сравнению с простой передачей по указателю/ссылке? Кому нужна копия - и сам ее сделает (а заодно и подумает есть ли лучшие решения). А изменить оригинал - все равно лочить. Не так уж легко привести пример где implicit дает какой-то выигрыш. А вот "ненужного изучения мнимых тонкостей" он добавляет немало.

Я где-то говорил, что Qt подходит для обучения азам программирования? Шокированный
К сожалению - слишком подходит  Улыбающийся
Записан
brankovic
Гость
« Ответ #19 : Август 16, 2011, 23:05 »

Да, я именно об этом и сказал. Выше указанная std::string нам тут безопасность не гарантирует.
Ну это легко обходится, давеча изучали  Улыбающийся

оффтоп: ссылку дайте на двеча, если не трудно. Или в 2х словах для проспавших, что именно std::string не гарантирует..

Edit: нашёл, почитал. Там про грязный хак с const_cast. А что std::string что-то не гарантирует это LisandreL ужасы какие-то рассказывает, gcc-шный std::string работает нормально.
« Последнее редактирование: Август 17, 2011, 10:47 от brankovic » Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #20 : Август 17, 2011, 00:16 »

А в чем эта безопасность, и что выиграли по сравнению с простой передачей по указателю/ссылке? Кому нужна копия - и сам ее сделает (а заодно и подумает есть ли лучшие решения). А изменить оригинал - все равно лочить. Не так уж легко привести пример где implicit дает какой-то выигрыш.
Цитата: cpp
void SomeClass::loadPixmap( ... )
{
    QPixmap pixmap;
    pixmap.load( path );
    emit pixmapReady( pixmap );
}
Считаем, что картинка у нас потенциально может быть большой.
Принципиально у нас могут быть 4 типа слота (мы пишем модуль, и какие в итоге из этих вариантов будут использоваться понятия не имеем):
1) slot1( QPixmap ) - коннект прямой, объект не изменяется;
2) slot2( QPixmap ) - коннект прямой, объект изменяется для дальнейшего внутреннего использования;
3) slot3( QPixmap ) - коннект через очередь (возможно другой поток), объект не изменяется;
4) slot4( QPixmap ) - коннект через очередь (возможно другой поток), объект изменяется для дальнейшего внутреннего использования.

а) Передавать по ссылке/указателю нельзя - когда вызовутся slot3 и slot4 объект уже будет разрушен.
Можно конечно породить объект динамически, но тогда не ясно, когда мы сможем его безопасно удалить.
Можно, конечно придумать систему обратной связи, но это сильно усложнит код на ровном месте.
Можно использовать умные указатели с подсчётом ссылок... упс, Qt-шные классы практически это за нас и делают.

б) Можно ли обойтись тут простыми классами без «implicit-sharing» и просто передавать по значению?
Безусловно.
Но, если у нас есть слоты типов slot1 и slot3 будет ненужное копирование и повышенный расход памяти, если слотов несколько.
В слотах slot3 и slot4, скорее всего будет ещё одно копирование при помещение в очередь.
Записан
lenny
Гость
« Ответ #21 : Август 17, 2011, 13:23 »

LisandreL. Хороший пример, уже смысл сего понятней, с потокобезопасностью я тоже не догнал.
« Последнее редактирование: Август 17, 2011, 13:27 от lenny » Записан
lenny
Гость
« Ответ #22 : Август 17, 2011, 13:26 »

К сожалению - слишком подходит  Улыбающийся
У меня более 10 лет стажа, к сожалению не очень развивающего. Типа много работы, короткие сроки и т.п.. В Qt дофига тонкостей. Это скорее для средних программеров, которым придется повышать квалификацию при использовании Qt.
« Последнее редактирование: Август 17, 2011, 13:31 от lenny » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #23 : Август 17, 2011, 14:11 »

Цитата: cpp
void SomeClass::loadPixmap( ... )
{
    QPixmap pixmap;
    pixmap.load( path );
    emit pixmapReady( pixmap );
}
Считаем, что картинка у нас потенциально может быть большой.
Принципиально у нас могут быть 4 типа слота (мы пишем модуль, и какие в итоге из этих вариантов будут использоваться понятия не имеем):
Должен признать что Ваши аргументы убедительны. Но с др. стороны - пример явно "учебный" (в этом нет ничего плохого). Это типично для Qt: если что-то по-быстрому соорудить - все великолепно, а вот если поглубже копнуть - то не очень Улыбающийся 

Напр маловероятно что в реальной задаче загрузчик картинок будет столь прост. Как правило он должен проверить не загружена ли уже такая картинка, и только если нет - загрузить и каким-то образом "зарегистрировать" чтобы не грузить ее потом опять. Если даже нет пользователей картинки, часто имеет смысл оставить ее в кэше. И вот если так начать копать, то быстро выяснится что лучше пусть загрузчик отвечает за удаление, а передать/эмиттить ее пользователям лучше по константной ссылке/указателю (вместо баловства с возвратом по значению)

Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #24 : Август 17, 2011, 14:55 »

Напр маловероятно что в реальной задаче загрузчик картинок будет столь прост. Как правило он должен проверить не загружена ли уже такая картинка, и только если нет - загрузить и каким-то образом "зарегистрировать" чтобы не грузить ее потом опять. Если даже нет пользователей картинки, часто имеет смысл оставить ее в кэше. И вот если так начать копать, то быстро выяснится что лучше пусть загрузчик отвечает за удаление, а передать/эмиттить ее пользователям лучше по константной ссылке/указателю (вместо баловства с возвратом по значению)
Такой подход применим, если мы целиком пишем программу.
Если мы пишем только модуль/класс и сигналы составляют на внешний интерфейс, то без лишней надобности плохо полагаться на то, что слот, который почистит за нами переданные данные будет и что он будет один.

Ну и хотелось бы услышать прочесть аргументы против такой организации данных, кроме того, что передача по значению не академична.
Считаете, что производительность сильно страдает? Или что-то ещё?
Записан
lenny
Гость
« Ответ #25 : Август 17, 2011, 19:58 »

В данном случае не академичена. Большинству и в голову не приходит передавать аргументу по значению и это уже на подсознательном уровне, а почему в данном случае так, приходится еще хорошо подумать.
« Последнее редактирование: Август 17, 2011, 20:02 от lenny » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #26 : Август 18, 2011, 06:25 »

Большинству и в голову не приходит передавать аргументу по значению и это уже на подсознательном уровне,
Дело в том что у многих "начитавшихся классов" это совсем не на подсознательном - ну и получается каша/говнокод.

Ну и хотелось бы услышать прочесть аргументы против такой организации данных, кроме того, что передача по значению не академична.
Считаете, что производительность сильно страдает? Или что-то ещё?
Например

Код
C++ (Qt)
void ProcessImage( QImage img )
{
..
uchar * bits = img.bits();
..
}
 
Код
C++ (Qt)
void ProcessContainer( Container <T> src )
{
..
for (Container <T> ::iterator it = src.begin(); it != src.end(); ++it)
..
}
 
Происходит неявное копирование, которое может обойтись весьма недешево. Но компилятор молчит, более того, это работает и не крашит. Заметим что даже в таких простейших случаях ошибка не бросается в глаза, в гораздо более запутанном реальном коде найти такое практически невозможно.

На мой взгляд очень немногие классы требуют sharing, даже в большом проекте, для подсчета хватает пальцев одной руки, поэтому их лучше расписать самому и покрасивше. А делать все классы shared - это, пардон, дешевый эффект.

Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #27 : Август 18, 2011, 08:02 »

>>Так подавляющее большинство классов Qt классов - это умный указатель на QИмяКлассаPrivate.
Не верное утверждение.
приватный класс совсем для других целей и умностью он совсем не наделён
Записан

Юра.
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #28 : Август 18, 2011, 08:09 »

Происходит неявное копирование, которое может обойтись весьма недешево.
Копирование происходит только в том случае, если на данные ссылается более 1 объекта.
Т.е. дорогое копирование произойдёт, только если раньше было присвоение одного объекта другому, а значит без sharing пресловутое дорогое копирование всё равно произошло бы, причём даже если мы использовали бы const uchar * bits = img.bits();.
Да, копирование произойдёт не в том участке кода, что иногда может быть критичным, но это уже довольно частный случай.

lit-uriy, умностью наделён указатель, а не класс. И да, не QИмяКлассаPrivate, а QИмяКлассаData.
Записан
lenny
Гость
« Ответ #29 : Август 18, 2011, 10:14 »

Происходит неявное копирование, которое может обойтись весьма недешево.
Копирование происходит только в том случае, если на данные ссылается более 1 объекта.
Т.е. дорогое копирование произойдёт, только если раньше было присвоение одного объекта другому, а значит без sharing пресловутое дорогое копирование всё равно произошло бы, причём даже если мы использовали бы const uchar * bits = img.bits();.
Да, копирование произойдёт не в том участке кода, что иногда может быть критичным, но это уже довольно частный случай.

lit-uriy, умностью наделён указатель, а не класс. И да, не QИмяКлассаPrivate, а QИмяКлассаData.
Механизм интересный, полностью скрывает себя от программиста.
Записан
Страниц: 1 [2] 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.199 секунд. Запросов: 23.