Итак, очередной выпуск журнала "Кодим Вместе".
Предлагаю немного отвлечься от насущных вопросов, и заняться чем-нибудь более медитативным и расслабляющим. Например, всем вместе реализовать известный дивный программистский паттерн -
фабрику.
На С++, конечно же, на чем же еще?
Итак, наш первый вариант:
//------------------------------------------------------------------
[Фабрика I] Вариант первый - брутальный struct MegaClass { }; class SomeFactory { public: MegaClass * CreateSmth() { return new MegaClass(); } };
|
| _Winnie C++ Colorizer |
Тоже ничего себе способ, довольно часто встречается, особенно среди любителей managed сред. Недостатки способа очевидны -
1. Можно легко допустить, чтобы кто-то прострелил себе ногу -
{ factory.CreateSmth(); } // утечка на пустом месте
|
Особенно если метод называется CreateMyMegaSuperObjectAndDoTenAnotherActions, принимает N параметров, и, кроме этого, еще делает M неочевидных действий;
2. Нечитабельно - факт передачи владения неочевиден.
//------------------------------------------------------------------
[Фабрик II] Вариант на "мягкую" четверку #include <memory> struct MegaClass { }; class SomeFactory { public: std::auto_ptr<megaclass> CreateSmth() { return std::auto_ptr<megaclass>(new MegaClass()); // он } };
|
Почему на четверку? Ибо налицо факт явного использования расширения C++. Стандарт C++ утверждает, что временный объект пользовательского типа представляет собой
modifyable rvalue. В терминах стандарта,
modifyable rvalue - это такая специальная сущность, у которой можно вызывать не константные методы, но которую никак нельзя связывать с не константными ссылками.
Т.е:
// пусть есть некоторое fnc void fnc(A & a) { /* определенно что-то делаем тут*/}
// тогда, для него A().fnc(); // так делать можно fnc(A()); // а так - не везде :)
|
Несложно заметить, что в этом варианте как раз и имеется попытка связывания временного обекта
std::auto_ptr<megaclass>(new MegaClass())
|
с не константной ссылкой - аргументом оператора присваивания (или конструктора копирования) класса std::auto_ptr
template<class> auto_ptr(auto_ptr<_other>& _Right); auto_ptr<_ty>& operator=(auto_ptr<_ty>& _Right);
|
Утешает только то, что в микрософтских компиляторах это расширение не отключается даже по /Za. А вот другие компиляторы вполне могут воспринимать такие творения более агрессивно:
/*
"ComeauTest.c", line 11: error: class "std::auto_ptr" has no suitable
copy constructor
return std::auto_ptr(new MegaClass());
^
*/
Посему - минус бал за непереносимость.
//------------------------------------------------------------------
[Фабрика III] Вариант - на пятерку
#include <memory> struct MegaClass { }; class SomeFactory { public: void CreateSmth(std::auto_ptr<MegaClass> * pResult) { pResult->reset(new MegaClass()); } };
|
Этот вариант лишен всех вышеописанных недостатков.
Делайте поменьше вредных выбросов.