2014-01-10 1 views
1

Существуют ли какие-либо существующие трюки для создания шаблонов декораторов на C++, которые проще использовать в отношении управления памятью?Как сделать шаблоны декоратора C++ проще в управлении памятью?

Если я использую std :: auto_ptr внутри моего декоратора, я могу создать объект в стиле вложенного нового, и указатели будут удалены должным образом. Однако, если я использую стиль передачи указателей на объекты, связанные с стекем, мы неправильно удаляем эти объекты. Есть ли способ сделать эту работу должным образом или обеспечить соблюдение только одного стиля?

#if 0 
    T0 t0; 
    T1 t1(&t0); 
    T2 t2(&t1); 
    T3 t3(&t2); 
#else 
    T3 t3(new T2(new T1(new T0))); 
#endif 

Я определил следующие простые классы испытаний.

#include <QDebug> 
#include <memory> 

class TI { 
public: 
    virtual void test() = 0; 
    virtual ~TI() {} 
}; 

class TD : public TI { 
public: 
    TD(TI *ti) : _ti(ti) {} 
    virtual void test() { return _ti->test(); } 
private: 
    std::auto_ptr<TI> _ti; 
}; 

class T0 : public TI { 
public: 
    T0() { qDebug("%s", __PRETTY_FUNCTION__); } 
    virtual void test() { qDebug("%s", __PRETTY_FUNCTION__); } 
    virtual ~T0() { qDebug("%s", __PRETTY_FUNCTION__); } 
}; 

class T1 : public TD { 
public: 
    T1(TI *ti) : TD(ti) { qDebug("%s", __PRETTY_FUNCTION__); } 
    virtual void test() { TD::test(); qDebug("%s", __PRETTY_FUNCTION__); } 
    virtual ~T1() { qDebug("%s", __PRETTY_FUNCTION__); } 
}; 

class T2 : public TD { 
public: 
    T2(TI *ti) : TD(ti) { qDebug("%s", __PRETTY_FUNCTION__); } 
    virtual void test() { TD::test(); qDebug("%s", __PRETTY_FUNCTION__); } 
    virtual ~T2() { qDebug("%s", __PRETTY_FUNCTION__); } 
}; 

class T3 : public TD { 
public: 
    T3(TI *ti) : TD(ti) { qDebug("%s", __PRETTY_FUNCTION__); } 
    virtual void test() { TD::test(); qDebug("%s", __PRETTY_FUNCTION__); } 
    virtual ~T3() { qDebug("%s", __PRETTY_FUNCTION__); } 
}; 
+0

C++ делает узор декоратора больным для использования, я избавился от всех из них в своем коде, я не рекомендую его, если только для существующего кода. – yngccc

+0

Не используйте 'std :: auto_ptr', это устарело, потому что небезопасно обрабатывать то же самое, что' std :: shared_ptr' равно – Mgetz

+0

@yngum: Это полезно для этого: 'ReadableKey (EncryptedKey (LicenseKey))' – Harvey

ответ

2

Согласно нашим правилам компании, ваш первый вариант требуется T0 t0; T1 t1(&t0);, так как создатель (абонент) несет ответственность, чтобы уничтожить элементы, он создал. В этом случае не имеет значения, экземпляры t0 и t1 создаются в куче или в стеке.

Вторая версия T3 t3(new T2(new T1(new T0))); звучит разумно, если можно полагаться на какую-то сборку мусора (например, C# делает или shared_ptr эмулирует). В конце идентификатор зависит от стиля кодирования и доступных фреймворков.

+0

Хорошая вещь о вложенных новостях - это возможность иметь фабричные методы для обычно используемых наборов: 'TD * t3210() {return new T3 (новый T2 (новый T1 (новый T0))); } '. Метод стека делает использование кода немного болью для других, поскольку он требует так много строк, что мешает читаемости их собственного кода. – Harvey

+0

Я полностью согласен с вами. Но реализация, вероятно, сложна. Как насчет добавления указателя на себя как члена класса и перезаписывания нового оператора для его хранения. Позже оператор удаления может проверить этот элемент и либо освободить память, либо ничего не делать. Это слишком сумасшедший? – dousin

+0

@ dousin: Совершенно сумасшедший, ИМХО. Этот член должен быть инициализирован в конструкторе, но это перезапишет назначение из 'operator new()'. Если вы хотите добавить чек в деструктор, просто добавьте переменную члена 'bool' и установите ее с помощью' t3.setDeleteOnDestroy() 'или что-то еще. – rodrigo

Смежные вопросы