А, я понял, почему. Ты создаёшь объект внутри, а дальше пытаешься из функции, возвращающей ссылку, вернуть этот созданный внутри объект. Да, тут мувы надо расставить.
TB>А почему тут омперсанды забыл?
TB>myQtLog& operator<<(QChar c) TB>итд
TB>А, я понял, почему. Ты создаёшь объект внутри, а дальше пытаешься из функции, возвращающей ссылку, вернуть этот созданный внутри объект. Да, тут мувы надо расставить.
Да, пользуясь уже готовым кодом и его операторами <<, пытаюсь вернуть, а вернее мувнуть, другой объект, у которого есть свои операторы <<, и который в своём деструкторе финализирует запись в логи.
С тем объектом есть проблема, что он тут должен быть только перемещаемым
Здравствуйте, Marty, Вы писали:
M>Решил избавится от скобочек при вызове лого-потока, и сделать глобальные объекты типа std::cout, доколбасил myQtLogStream M>Не работает
Если я правильно понимаю, вот здесь:
myQtLog operator<<(char c) { return std::move( mkLog()<<c); }
создаётся объект myQtLog,
потом он мувится в другой объект myQtLog
затем вызывается деструктор ~myQtLog()
в котором вызываются функции от уже смувленных (пустых) членов класса.
Поэтому не работает.
А в чём вопрос?
Здравствуйте, T4r4sB, Вы писали:
TB>Но это длиннее
Не прокатило. В итоге, всё перевёл в MyLogImpl, а MyLog храню только QSharedPointer<MyLogImpl>. Так работает. Но хочется понять, как бы сделать без шаред птр
Здравствуйте, Marty, Вы писали:
BFE>>Если я правильно понимаю, вот здесь: BFE>>
BFE>>myQtLog operator<<(char c) { return std::move( mkLog()<<c); }
BFE>>
BFE>>создаётся объект myQtLog, BFE>>потом он мувится в другой объект myQtLog BFE>>затем вызывается деструктор ~myQtLog()
M>Разве деструктор должен вызываться? мув вроде как раз против этого и придуман
Не-а. Он переносит (может переносить) содержимое одного объекта в другой. В некорректной аналогии move — это swap с пустым объектом. Так что для каждого вызванного конструктора должен быть вызван деструктор.
M>Если так M>
M>myQtLog operator<<(char c) { return mkLog()<<c; }
M>
M>Тоже не работает
И не должно, если я правильно понимаю: в возвращённом объекте, в m_stream, будет хранится указатель на уничтоженную строку.
BFE>>в котором вызываются функции от уже смувленных (пустых) членов класса. BFE>>Поэтому не работает. M>Нет, не поэтому
А почему?
BFE>>А в чём вопрос? M>Как сделать правильно
Это зависит от того, что называть "правильно".
Например, приложение собранное с
DEFINES += QT_NO_DEBUG_OUTPUT
в .pro выкинет весь qDebug() вывод (и некоторые вызовы для этого вывода). Это правильно или нет?
Ещё иногда считают, что использовать не константные глобальные объекты — не правильно. Бывают даже ситуации, когда std::cout используется до создания, что приводит к падению на старте.
Так что вы понимаете под "правильно"?
M>>Разве деструктор должен вызываться? мув вроде как раз против этого и придуман BFE>Не-а. Он переносит (может переносить) содержимое одного объекта в другой. В некорректной аналогии move — это swap с пустым объектом. Так что для каждого вызванного конструктора должен быть вызван деструктор.
А можно корректную аналогию? А то у меня сложилось впечатление, что move — это "swap" с неинициализированным объектом
M>>Если так M>>
M>>myQtLog operator<<(char c) { return mkLog()<<c; }
M>>
M>>Тоже не работает BFE>И не должно, если я правильно понимаю: в возвращённом объекте, в m_stream, будет хранится указатель на уничтоженную строку.
Не работает потому, что не канпиляеца
BFE>>>в котором вызываются функции от уже смувленных (пустых) членов класса. BFE>>>Поэтому не работает. M>>Нет, не поэтому BFE>А почему?
Не канпиляеца
BFE>>>А в чём вопрос? M>>Как сделать правильно BFE>Это зависит от того, что называть "правильно".
Смотри. Я хочу завести глобальные объекты myDebug/myInfo/myWarning/etc типа MyLogStream. У MyLogStream есть operator<<, который возвращает экземпляр MyLog, перед этим вызвав его operator<< для переданного аргумента.
В свою очередь, MyLog пишет всё в свой буфер, и в деструкторе финализирует запись и сливает строку в кутишный лог с ссотвествующим левелом. Сейчас я решил вопрос, заведя MyLogImpl, в котором делается реальная работа, а в MyLog храню только QSharedPointer<MyLogImpl>. Теперь CTOR копирования и operator= работают по умолчанию, и ничего мутить не надо. Использование выглядит так:
Тут вызывается operator<< для глобального объекта myDebug/myInfo, там создаётся новый MyLog и для него вызывается operator<<. Затем это MyLog возвращается, и последующие operator<< вызываются уже для него. В конце выражения MyLog уничтожается, в деструкторе мембера, который лежит в шаред поинтере, производится запись всего сообщения в кутишный лог с соответсвующим уровнем.
Правильно, в данном случае — это используя мув семантику современных плюсиков, реализовать всё то же, но без использования шаред поинтера
BFE>Например, приложение собранное с BFE>DEFINES += QT_NO_DEBUG_OUTPUT BFE>в .pro выкинет весь qDebug() вывод (и некоторые вызовы для этого вывода). Это правильно или нет?
А info/warning/critical/fatal — тоже выкинет? Если да, то это — неправильно.
Но я не понял, к чему сейчас это было
BFE>Ещё иногда считают, что использовать не константные глобальные объекты — не правильно. Бывают даже ситуации, когда std::cout используется до создания, что приводит к падению на старте. BFE>Так что вы понимаете под "правильно"?
Под "правильно" я понимаю не лезть со своей демагогией, если по существу сказать нечего
Здравствуйте, Marty, Вы писали:
M>Но хранить состояние валидности в чужом enum'е — тоже не самая лучшая идея
Идея не в этом.
Идея в том, что хранить состояние. А в чем именно — это уже твое дело.
Я просто малой кровью твой код исправил и все. Нужно это понимать.
Вот тут есть один интересный нюансик. В твоей первой версии у тебя под return-ами стояли prvalue выражения и на них распространялись требования Mandatory copy/move elision. Такие return-ы благополучно компилируются даже при отсутсвии copy- move- конструктов в типах возвращаемых значений. Как только ты добавил std:move, выражения под return-ами стали относиться к категории xvalue, на которые уже не распространяется требование mandatory copy/move elision. Компиляторам хоть и разрешается применять оптимизации RVO/NRVO для таких вырахений, но наличие copy или move конструктора в типе возвращаемого значения является обязательным.