[C++] туплю про ссылки и временные объекты
объект Streamer, который по идее должен создаваться как временный только из логгера, в него что-то там выводится, и в конце выражения он уничтожается и выводит все в логкривой дизайн, ибо логика в деструкторе и есть неконтролируемый процесс создания копий объектов. как следствие однажды получишь в логах пустые строчки, которые ты не надеялся там увидеть. с копированием можно пободаться, введя move конструктор и запретив копирование. в деструкторах же надо как минимум гарантировать отсутствие исключений, иначе приложуха может падать при double exception
в целом, странно, что оно у тебя компилируется, ибо конструктор копии недоступен (приватен). см пример: http://ideone.com/7HF5Ml
Казалось бы, странное ограничение, и наверное его как-то можно обойти, не вызывая фейковый operator <<действительно, странное, но такие уж правила игры. чуток недавно обсуждали здесь:
если я контролирую класс Streamer, я могу приделать к нему какую-то странную функциюможно еще навесить const на метод << , объявить s как mutable и передавать const ссылку в функцию debug
Попытки кастовать пока не компилируютсяпопробуй через могучий "оператор" ZZZ : http://ideone.com/3iTTHi
вроде даже должно работать
кривой дизайн, ибо логика в деструкторе и есть неконтролируемый процесс создания копий объектов. как следствие однажды получишь в логах пустые строчки, которые ты не надеялся там увидеть. с копированием можно пободаться, введя move конструктор и запретив копирование. в деструкторах же надо как минимум гарантировать отсутствие исключений, иначе приложуха может падать при double exceptionМожно примеры этого "однажды", которое я получу? Мне кажется, что способ использования объекта довольно ограничен, чтобы получить нечто неожиданное.
С исключениями в деструкторе легко побороться, проверяя std::uncaught_exception но это не тема моего вопроса.
С копированием не надо бодаться, т.к. оно нужно только при вызове Logger::log, когда строка в объекте пустая, там почти ничего не копируется.
в целом, странно, что оно у тебя компилируется, ибо конструктор копии недоступен (приватен)Там friend стоит, иначе было бы странно, что объект вообще создается, конструктор же тоже приватный.
можно еще навесить const на метод << , объявить s как mutable и передавать const ссылку в функцию debugИ еще навесить const_cast на возвращаемый *this, что в целом производит отвратительное впечатление.
попробуй через могучий "оператор" ZZZС ZZZ работает, спасибо.
И еще навесить const_cast на возвращаемый *thisнавешивать не понадобится : надо вернуть const ссылку на объект
Happy debugging?debug(logger.log;
Нельзя так писать.
Поясни, почему нельзя. Если тебе название "debug" не нравится, так это просто пример функции, которая хочет на вход ссылку на какой-нибудь стример получить.
Поясни, почему нельзя.Мне что-то подсказывает, что debug — это макрос, который в сборке релизной не сделает вызов.
Можно примеры этого "однажды", которое я получу?дело в том, что конструкторы копирования - это спец методы и в некоторых сценариях компилятор волен (стандарт явно это оговаривает) вызывать их неограниченное число раз, даже если там есть сайд-эффекты. об этом можно почитать, например, тут: http://en.wikipedia.org/wiki/Return_value_optimization . там даже есть пример, который печатает разные вещи в зависимости от того, как отработал компилятор.
конкретно твой пример даже на практике (а не только в теории) может выдавать разные вещи
я играл тут: http://coliru.stacked-crooked.com/
при таком запуске
g++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.outимеем выхлоп
1410247766 debugа при таком запуске
g++ -std=c++11 -O2 -Wall -fno-elide-constructors -pedantic -pthread main.cpp && ./a.outимеем выхлоп
1410247191если тебе важно качество кода и отсутствие wtf от коллег в будущем, то желательно учитывать подобные нюансы языка
1410247191 debug
как метод решения я бы предложил
1) убрать определение конструктора копирования (объявление при этом следует оставить). в этом случае. если компилятор все же попытается заюзать конструктор, то линковка сломается (грязновато, но как страховка сойдет)
2) поддержать неограниченное кол-во копий (для этого можно stringstream держать по указателю и при копированиии шарить этото указатель)
3) поддержать move и запретить копирование. есть гарантии, что рабочий объект будет всего один (даже если move вызвался много раз а пустышки не должны пытаться что-то напечатать в деструкторе
с деструкторами дольше разжевывать, проще тебе погуглить
Оставить комментарий
erotic
Есть такой код:Суть в следующем: у нас есть логгер, который умеет за раз вывести строчку с какой-то дополнительной информацией типа времени, и есть объект Streamer, который по идее должен создаваться как временный только из логгера, в него что-то там выводится, и в конце выражения он уничтожается и выводит все в лог, например, так:
Странная для меня штука заключается в том, что при наличии функции типа debug в моем коде я не могу просто так передать в нее этот Streamer, поскольку функция требует неконстантной ссылки, а объект у меня временный, но при этом я могу это сделать, если выведу в Streamer ну хотя бы пустую строку, и оператор вернет уже нормальную ссылку на объект.
Казалось бы, странное ограничение, и наверное его как-то можно обойти, не вызывая фейковый operator << . Понятно, что если я контролирую класс Streamer, я могу приделать к нему какую-то странную функцию типа
и вызывать так:
Но что, если изменять Streamer я не могу? Попытки кастовать пока не компилируются, например, такие: