Size: a a a

2020 February 16

O

Ofee in Qt
Anatoly Shirokov
Попробуй внешние тулы типа dr.memory, они ошибки по работе с памятью тебе подкинут. А так у тебя расстрел памяти, трудноуловимый случай.
Спасибо, попробую
источник

BB

Bohdan Bessonov in Qt
Ofee
Дело в том, что ни сырых массивов, ни сырых указателей у меня в коде вообще нет. Если только я где-то что-то опасное с итератормаи сделал...
Всё, что сумел определить — что изменения участка кода с непосредственным вызовом моего коллбека то ли решает проблему, то ли просто скрывает от меня...
Отсутствие указателей не мешает УБшить)
Наверное, надо уже детально смотреть в код, если это возможно и не нарушает всякие нда
источник

Е

Егор in Qt
Ofee
Дело в том, что ни сырых массивов, ни сырых указателей у меня в коде вообще нет. Если только я где-то что-то опасное с итератормаи сделал...
Всё, что сумел определить — что изменения участка кода с непосредственным вызовом моего коллбека то ли решает проблему, то ли просто скрывает от меня...
А других либ кроме кутей нету?
источник

O

Ofee in Qt
Bohdan Bessonov
Отсутствие указателей не мешает УБшить)
Наверное, надо уже детально смотреть в код, если это возможно и не нарушает всякие нда
Увы, нарушает, часть модулей я могу без проблем открыть, а часть нет, из-за этого и затруднено создание минимально-воспроизводимого примера. Пока что в текущем виде могу только исходник моего класса дать, который и должен вызывать интересующий меня коллбек в интересующей очереди событий
источник

BB

Bohdan Bessonov in Qt
Ofee
Увы, нарушает, часть модулей я могу без проблем открыть, а часть нет, из-за этого и затруднено создание минимально-воспроизводимого примера. Пока что в текущем виде могу только исходник моего класса дать, который и должен вызывать интересующий меня коллбек в интересующей очереди событий
Можно попробовать просимулировать все же с примером, изолировать проблемный код и проверить как раз

Если нет - мемори профайлеры только и статик анализаторы(
источник

AS

Anatoly Shirokov in Qt
Ofee
Столкнулся с тем, что у меня this, переданный в лямбду, становится невалиден. Вызов переданной лямбды делается таким образом:
template<typename... Args>
void call_impl(Args&&... args) const
{
 QMetaObject::invokeMethod(
   context,  
   [this, args = std::tuple(std::forward<Args>(args)...)]() mutable {
     std::apply(callback, std::move(args));
   },
   Qt::ConnectionType::QueuedConnection);
}
context
в данном случае — это QAbstractEventDispatcher*, я его получаю через QAbstractEventDispatcher::instance(); однократно при создании моего объекта.
Замена тела на std::apply(callback, std::tuple(std::forward<Args>(args)...));  исправляет падение, но я не очень понимаю, в какую сторону дальше копать в поисках причины.

Возможно, вы дадите мне направление или, может, даже у кого-то хватит экстрасенсорных способностей, чтобы сразу найти у меня ошибку...
Если нужно будет, полный код моего класса выложу, а вот с минимально-воспроизводимым примером труднее — баг стабильно воспроизводится в моём приложении, однако как его повторить в упрощённом — не знаю.

Ну, и важное уточнение: воспроизводится и при работе в одном потоке, и в нескольких
А ты можешь объяснить зачем тебе move, когда там должен быть forward? Ты понимаешь разницу move/forward?

template<typename T> void foo(T&&v); // forward
void boo(int&& v); // move
источник

Е

Егор in Qt
Ofee
Столкнулся с тем, что у меня this, переданный в лямбду, становится невалиден. Вызов переданной лямбды делается таким образом:
template<typename... Args>
void call_impl(Args&&... args) const
{
 QMetaObject::invokeMethod(
   context,  
   [this, args = std::tuple(std::forward<Args>(args)...)]() mutable {
     std::apply(callback, std::move(args));
   },
   Qt::ConnectionType::QueuedConnection);
}
context
в данном случае — это QAbstractEventDispatcher*, я его получаю через QAbstractEventDispatcher::instance(); однократно при создании моего объекта.
Замена тела на std::apply(callback, std::tuple(std::forward<Args>(args)...));  исправляет падение, но я не очень понимаю, в какую сторону дальше копать в поисках причины.

Возможно, вы дадите мне направление или, может, даже у кого-то хватит экстрасенсорных способностей, чтобы сразу найти у меня ошибку...
Если нужно будет, полный код моего класса выложу, а вот с минимально-воспроизводимым примером труднее — баг стабильно воспроизводится в моём приложении, однако как его повторить в упрощённом — не знаю.

Ну, и важное уточнение: воспроизводится и при работе в одном потоке, и в нескольких
А callback не константная функция случайно? Может там конфликт с mutable лямбдой и конст квалифаером где-то?
источник

O

Ofee in Qt
Anatoly Shirokov
А ты можешь объяснить зачем тебе move, когда там должен быть forward? Ты понимаешь разницу move/forward?

template<typename T> void foo(T&&v); // forward
void boo(int&& v); // move
Тут я могу делать что-то неправильно, я немного застопорился на попытке сделать форвард внутрь захвата лямбды. Но на практике выяснилось, и move и forward для args имеют одинаковое поведение и я, честно говоря, даже забыл про эту строку

Вот полный код самого класса. Местами могут быть, возможно, странные решения, я, честно говоря, пока хотел по-больше поэкспериментировать
источник

Е

Егор in Qt
Ofee
Тут я могу делать что-то неправильно, я немного застопорился на попытке сделать форвард внутрь захвата лямбды. Но на практике выяснилось, и move и forward для args имеют одинаковое поведение и я, честно говоря, даже забыл про эту строку

Вот полный код самого класса. Местами могут быть, возможно, странные решения, я, честно говоря, пока хотел по-больше поэкспериментировать
А если у лямбды mutable квалифаер убрать, так же крашится?
источник

O

Ofee in Qt
Егор
А callback не константная функция случайно? Может там конфликт с mutable лямбдой и конст квалифаером где-то?
Хм, у меня в действительности там умный указатель на std::function, я вот только сейчас в качестве эксперимента попробовал хранить напрямую std::function
источник

O

Ofee in Qt
Егор
А если у лямбды mutable квалифаер убрать, так же крашится?
Полагаю, мне нужно какое-то время, чтобы решить ошибки сборки и выяснить. Вообще, интересная мысль, спасибо
источник

AS

Anatoly Shirokov in Qt
Ofee
Тут я могу делать что-то неправильно, я немного застопорился на попытке сделать форвард внутрь захвата лямбды. Но на практике выяснилось, и move и forward для args имеют одинаковое поведение и я, честно говоря, даже забыл про эту строку

Вот полный код самого класса. Местами могут быть, возможно, странные решения, я, честно говоря, пока хотел по-больше поэкспериментировать
#include <string>
#include <iostream>

template<typename T>
void eat(T&&) {
}
template<typename T>
void foo(T&& t) {
  eat(std::move(t));
}
int main() {
 std::string s{"123456678901234566789012345667890"};
 foo(s);
 // что выведется в консоль?
 std::cout << s;
}
источник

O

Ofee in Qt
Anatoly Shirokov
#include <string>
#include <iostream>

template<typename T>
void eat(T&&) {
}
template<typename T>
void foo(T&& t) {
  eat(std::move(t));
}
int main() {
 std::string s{"123456678901234566789012345667890"};
 foo(s);
 // что выведется в консоль?
 std::cout << s;
}
Если не ошибаюсь, в данном случае — ничего
источник

AS

Anatoly Shirokov in Qt
Ofee
Если не ошибаюсь, в данном случае — ничего
итого, ты move-ом разрушаешь объект, который при прочих условиях не должен быть разрушен
источник

Е

Егор in Qt
Ofee
Если не ошибаюсь, в данном случае — ничего
а у меня вывело строку
источник

O

Ofee in Qt
Anatoly Shirokov
итого, ты move-ом разрушаешь объект, который при прочих условиях не должен быть разрушен
Корректна ли в моем случае такая передача?
std::forward<decltype(args)>(args)
источник

AS

Anatoly Shirokov in Qt
Ofee
Корректна ли в моем случае такая передача?
std::forward<decltype(args)>(args)
да
источник
2020 February 17

O

Ofee in Qt
Могу что-то не учитывать, но на практике выходило, что поведение у них идентичное. Поскольку в value-категориях я всё ещё немного плаваю, легче продемонстрировать кодом:
QEventLoop e; 
// Так же может быть MyClass или MyClass&&
// но никогда не MyClass&, ибо это не будет работать

Async<MyClass> async = [&](MyClass const&s){
   std::cout << "In lambda: " << s << std::endl; //
   e.quit();
};


MyClass f{"42"};
async(f); // Вызывается один конструктор копирования
async(MyClass{"42"}); // Вызывается один оператор перемещения


Дальше уже непосредственно в недрах Qt происходят перемещения моего объекта вместе с tuple, переданным в лямбду
источник

O

Ofee in Qt
Ofee
Могу что-то не учитывать, но на практике выходило, что поведение у них идентичное. Поскольку в value-категориях я всё ещё немного плаваю, легче продемонстрировать кодом:
QEventLoop e; 
// Так же может быть MyClass или MyClass&&
// но никогда не MyClass&, ибо это не будет работать

Async<MyClass> async = [&](MyClass const&s){
   std::cout << "In lambda: " << s << std::endl; //
   e.quit();
};


MyClass f{"42"};
async(f); // Вызывается один конструктор копирования
async(MyClass{"42"}); // Вызывается один оператор перемещения


Дальше уже непосредственно в недрах Qt происходят перемещения моего объекта вместе с tuple, переданным в лямбду
Т.е. если я правильно понимаю происходящее, всё, что нужно, perfect forwarding сделал при вызове конструктора std::tuple, дальше уже у меня либо лежит копия, которую можно мувать без боязни, либо объект, в который  мы только что смували, разрушив оригинальный rvalue

Прошу поправить, если я не прав
источник

BB

Bohdan Bessonov in Qt
Anatoly Shirokov
#include <string>
#include <iostream>

template<typename T>
void eat(T&&) {
}
template<typename T>
void foo(T&& t) {
  eat(std::move(t));
}
int main() {
 std::string s{"123456678901234566789012345667890"};
 foo(s);
 // что выведется в консоль?
 std::cout << s;
}
А можно этот пример объяснить для общего развития?
(Мув скастует лвалуе реф в рвалуе реф, почему это разрушит строку? Мув же не гарантирует разрушение?)
источник