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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Signal/Slot rvalue  (Прочитано 7372 раз)
AlphaGh0St
Гость
« : Март 08, 2016, 19:52 »

Всем привет!
После переустановки винды и установки нового QtCreator'a 3.6.0 c Qt 5.5.1, по лбу мне ударили грабли, которых я никак не ожидал.

Набросал простенький код с целью демонстрации проблемы. В чём суть:
Есть некий класс class Object;
Сигналим им по ссылке и принимаем в слоте по ссылке. Ссылка не константная, т.к. объект модифицируется в слоте.
Код:
Q_SIGNALS:
    void ObjSig(Object& obj);

private Q_SLOTS:
    void OnObjSig(Object& obj);

// подключаем
connect(this, SIGNAL(ObjSig(Object&)), this, SLOT(OnObjSig(Object&)));

// генерируем сигнал
emit ObjSig(Object(0, "test"));

Раньше этот код собирался и работал нормально. Сейчас же вылетает такой сюрприз:
Цитировать
ошибка: no matching function for call to 'MainWindow::ObjSig(Object)'
candidate is:
void MainWindow::ObjSig(Object&)
note:   no known conversion for argument 1 from 'Object' to 'Object&'
Оказывается, НЕТ такой функции, и, с какой-то радости, теперь передача идёт по значению, а ссылки вот вроде бы как, компилятор, и не заметил случайно.

Погуглив, выяснил, что теперь нужно использовать семантику перемещения, а описанный выше код уже не корректен. Ну ОК. Переделал:
Код:
Q_SIGNALS:
    void ObjSig(Object&& obj);

private Q_SLOTS:
    void OnObjSig(Object&& obj);

// подключаем
connect(this, SIGNAL(ObjSig(Object&&)), this, SLOT(OnObjSig(Object&&)));

// генерируем сигнал
emit ObjSig(Object(0, "test"));
И вот тут-то по лбу и ударили те самые грабли, набив такую шишку, на которую пол дня потратил и даже гугл ничем не помог. "Осчастливил" creator меня сей радостным сообщением:
Цитировать
// в мос_файле
case 0: _t->ObjSig((*reinterpret_cast< Object(*)>(_a[1]))); break;
case 1: _t->OnObjSig((*reinterpret_cast< Object(*)>(_a[1]))); break;

In static member function 'static void MainWindow::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)':
ошибка: cannot bind 'Object' lvalue to 'Object&&'
In file included from debug\moc_mainwindow.cpp:9:0:

initializing argument 1 of 'void MainWindow::ObjSig(Object&&)'
ошибка: cannot bind 'Object' lvalue to 'Object&&'
In file included from debug\moc_mainwindow.cpp:9:0:
initializing argument 1 of 'void MainWindow::OnObjSig(Object&&)'

Я морально истощён и уже просто не знаю, что делать, кроме как биться об стену головой.
Гугл, как частенько бывает, оказался бесполезным.

Как можно решить эту проблему?
Благодарю.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #1 : Март 09, 2016, 14:18 »

Вы уверены, что в данном случае, правильно используете сигнал-слот взаимодействие? Подходит ли оно для того, чтобы изменять объект по ссылке?

Оказывается, НЕТ такой функции, и, с какой-то радости, теперь передача идёт по значению, а ссылки вот вроде бы как, компилятор, и не заметил случайно.

Может компилятор как раз и заметил, и разработчики, написав такую сигнатуру для метода, указывают, что можно в него передавать, а что нельзя. Синтаксис С++11 позволяет лучше это делать. Например, объект с сигналом ObjSig и объект со слотом OnObjSig находятся в разных потоках. Что произойдёт в этом OnObjSig, когда дело дойдёт до обращения к Object& obj по ссылке?
« Последнее редактирование: Март 09, 2016, 16:14 от ViTech » Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Март 09, 2016, 14:54 »

А почему не так
Код
C++ (Qt)
Object temp(0, "test");
emit ObjSig(temp);
Вообще - если передается по неконстантной ссылке, то ожидается изменение этого параметра которое, наверное, вызывающий будет использовать. А у Вас другая логика вызывающего, тогда уж объявляйте константной ссылкой
Записан
AlphaGh0St
Гость
« Ответ #3 : Март 10, 2016, 01:13 »

Так можно, и это сработает.
Код:
Object temp(0, "test");
emit ObjSig(temp);
Но не хочу так делать исключительно из эстетических соображений. Мне однострочники больше нравятся.
Просто передаём объект по ссылке и нас уже не интересует, что с ним будет и каким модификациям он будет подвержен. Потому так спокойно передаю и не беспокоюсь.

Проблема остаётся открытой. Если кто-нибудь сталкивался с подобным и нашёл решение, поделитесь им, пожалуйста.
Записан
AlphaGh0St
Гость
« Ответ #4 : Март 10, 2016, 01:18 »

Забыл сказать в предыдущем сообщении. Собственно, верное замечание, что в данном случае следует передавать константной ссылкой. Но если передавать константной ссылкой, разве можно будет проводить какие-то модификации над переданным объектом?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #5 : Март 10, 2016, 02:24 »

Забыл сказать в предыдущем сообщении. Собственно, верное замечание, что в данном случае следует передавать константной ссылкой. Но если передавать константной ссылкой, разве можно будет проводить какие-то модификации над переданным объектом?

const_cast еще никто не запрещал Улыбающийся
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Bepec
Гость
« Ответ #6 : Март 10, 2016, 08:13 »

Вообще очень опасная ситуация возникает при таком подходе, мало того, она как ружьё, заряженное на стенке - выстрелит обязательно. Никто не знает когда и куда дойдёт сигнал, сколько получателей и какие потоки.
Я б советовал поменять архитектурку.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #7 : Март 10, 2016, 09:50 »

Яб посоветовал почитать стандарт и узнать, что rvalue не приводится к неконст ссылке, а компилятор, позволяющий делать так, стоит выкинуть на помойку (да, я про студию)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Март 10, 2016, 11:47 »

Просто передаём объект по ссылке и нас уже не интересует, что с ним будет и каким модификациям он будет подвержен. Потому так спокойно передаю и не беспокоюсь.
А это логика передачи по значению

Проблема остаётся открытой. Если кто-нибудь сталкивался с подобным и нашёл решение, поделитесь им, пожалуйста.
Похоже Вы ищете пятый угол. Пример без всяких слот-сигналов
Код
C++ (Qt)
void Func1( Object & obj );
..
Func1(Object());  // error: non-const reference initialized to temporary
Т.е. так нельзя по правилам языка
Код
C++ (Qt)
void Func2( const Object & obj );
..
Func2(Object());  // а теперь так можно
Object obj;
Func2(obj);  // и так можно
 
Как известно смысл передачи по константой ссылке двоякий - может быть временный объект или нет. Ну и выберите то что соответствует логике Вашей задачи. А то вызываемый видит одно, вызывающий другое - зачем пытаться этого достичь? Если нужны оба варианта - заведите 2 сигнала, это правильно.
« Последнее редактирование: Март 10, 2016, 11:49 от Igors » Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #9 : Март 10, 2016, 12:21 »

Но не хочу так делать исключительно из эстетических соображений. Мне однострочники больше нравятся.
Просто передаём объект по ссылке и нас уже не интересует, что с ним будет и каким модификациям он будет подвержен. Потому так спокойно передаю и не беспокоюсь.
Подозреваю, что с таким спокойствием вам ещё много грабель предстоит встретить Улыбающийся.

Цитата: AlphaGh0St
Собственно, верное замечание, что в данном случае следует передавать константной ссылкой. Но если передавать константной ссылкой, разве можно будет проводить какие-то модификации над переданным объектом?

Можно поинтересоваться, зачем в слоте модифицировать объект, переданный из сигнала вообще, и по ссылке в частности? И ещё раз предлагаю подумать. Допустим, всё собралось так, как вы хотите и объект передаётся по ссылке. Пусть всё даже происходит в одном потоке. Если мы соединим сигнал с двумя слотами, первый слот модифицирует объект, то что получит второй слот: исходный объект из сигнала или с модификациями из первого слота?
Записан

Пока сам не сделаешь...
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #10 : Март 10, 2016, 12:28 »

как-то бессмысленно модифицировать временный объект, созданный в однострочнике, разве нет?
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #11 : Март 10, 2016, 13:02 »

Если основная идея - модифицировать объект в слоте... то надо быть уверенным, что это единственный слот, связанный с данным сигналом. Иначе последствия могут быть не очень предсказуемы Улыбающийся
Ну и используйте поинтер, в самом деле.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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