2017-02-02 3 views
2

Для образовательных целей, я был ранее сегодня реализует класс обертку, определенный ниже (это взято из книги):Простой класс-оболочка против смарт-указатель

#ifndef WRAPPER_H 
#define WRAPPER_H 

template<class T> 
class Wrapper 
{ 
public: 
    Wrapper() 
    { dataPtr = 0; } 

    Wrapper(const T& inner) 
    { 
    dataPtr = inner.clone(); 
    } 

    Wrapper(const Wrapper<T> &original) 
    { 
    if (original.dataPtr != 0) 
     dataPtr = original.dataPtr->clone(); 
    else 
     dataPtr = 0; 
    } 

    Wrapper &operator =(const Wrapper<T> &original) 
    { 
    if (this != &original) 
    { 
     if (dataPtr != 0) 
      delete dataPtr; 

     dataPtr = (original.dataPtr !=0) ? original.dataPtr->clone() : 0; 
    } 
    return *this; 
    } 

    ~Wrapper() 
    { 
    if (dataPtr != 0) 
     delete dataPtr; 
    } 

    T &operator*() 
    { 
    return *dataPtr; 
    } 

    const T&operator*() const 
    { 
    return *dataPtr; 
    } 

    T *operator->() 
    { 
    return dataPtr; 
    } 

    const T * const operator->() const 
    { 
    return dataPtr; 
    } 
private: 
    T *dataPtr; 
}; 

#endif 

Основная идея заключается в том, чтобы действовать в качестве указателя , с дополнительным преимуществом по уходу за памятью, конструктором копирования, деструктором и оператором присваивания. Он обертывает классы, которые имеют метод клонирования: они возвращают указатель на копию самих себя (не для себя, для новой копии, сделанной с newClass(*this)).

В некотором роде это похоже на unique_ptr, поскольку обернутый объект доступен только через эту оболочку. Однако есть разница, о чем мой вопрос. В этом классе-оболочке существует конструктор, определяемый путем принятия ссылки на объект класса, который он обертывает (первый конструктор в приведенном выше коде).

Это очень удобно. Предположим, что у нас есть классы A и B, а конструктор для B ссылается на Wrapper<A>. Тогда можно построить объект B с другим объектом A:

A object1; 
B object2(A); 

Это потому, что object2 используется для построения Wrapper<A> (затем передается в конструктор B) с использованием указанного выше Wrapper конструктора.

Возможно ли это сделать с помощью любого из умных указателей в std::memory? Моя главная цель здесь - образовательная, но на практике я не хочу изобретать велосипед.

+1

Копировальный конструктор недоступен для уникальных указателей, поскольку после копии они больше не будут уникальными. Вместо общих указателей вместо _copyable_, где копия просто обеспечивает тот факт, что они _share_ являются собственностью заостренного объекта. – skypjack

+0

Похоже, что он делает глубокие копии, а не передает/перемещает указатель. – user4581301

+0

Похож на intrusive_ptr –

ответ

5

умный указатель предназначен для обеспечения собственности семантику, которая может быть категоризированы (и имеют доступные стандартные реализации C++):

  • уникальный собственности всегда передается при прохождении вокруг
  • совместно Там нет одного владельца, смарт-указатель имеет значение ссылки, и болезней, если они падают на 0
  • слабой Зависимый указатель, но предлагающий возможность проверить, сохранен ли указанный указатель

Это сильно отличается от вашей реализации оболочки.

1

да все это возможно .. и для справки .. и потому, что однажды я также реализовал нечто подобное .. (для образовательных целей тоже). Я могу поделиться кодом, который я сделал для smartpointer, с подсчетом ссылок. . означает, что вы можете создать столько его копий, как вы хотите, что, когда последняя копия уничтожается будет удалить объект

#ifndef UberPointer 
#define UberPointer UPointer 

template <class UClass> class UPointer 
{ 
private: 
    struct UPointerRef 
    { 
     UClass* pObject; 
     int _nCount; 
     UPointerRef(UClass* pRef){_nCount=0;pObject = pRef;} 
     ~UPointerRef(){if(pObject)delete pObject;} 
     void AddRef(void){++_nCount;} 
     void RemoveRef(void){if (--_nCount <= 0){delete this;}} 
    }; 
    UPointerRef* _pRef; 

public: 
    UPointer() 
    { 
     _pRef = new UPointerRef(0x0); 
     _pRef->AddRef(); 
    } 
    UPointer(UClass* pPointer) 
    { 
     _pRef = new UPointerRef(pPointer); 
     _pRef->AddRef(); 
    } 
    UPointer(UPointer<UClass> &oPointer) 
    { 
     _pRef = oPointer._pRef; 
     _pRef->AddRef(); 
    } 
    ~UPointer(void) 
    { 
     _pRef->RemoveRef(); 
    } 
    UClass* GetObject() 
    { 
     ASSERT(_pRef->pObject); 
     return _pRef->pObject; 
    } 
    operator UClass*(void) 
    { 
     ASSERT(_pRef->pObject); 
     return _pRef->pObject; 
    } 
    UClass& operator*(void) 
    { 
     ASSERT(_pRef->pObject); 
     return *(_pRef->pObject); 
    } 
    UClass* operator->(void) 
    { 
     ASSERT(_pRef->pObject); 
     return (_pRef->pObject); 
    } 
    UPointer& operator=(UPointer<UClass> &oPointer) 
    { 
     _pRef->RemoveRef(); 
     _pRef = oPointer._pRef; 
     _pRef->AddRef(); 
     return *this; 
    } 
    UPointer& operator=(UClass* pPointer) 
    { 
     _pRef->RemoveRef(); 
     _pRef = new UPointerRef(pPointer); 
     _pRef->AddRef(); 
     return *this; 
    } 
    bool operator==(UClass* pPointer) 
    { 
     return _pRef->pObject == pPointer; 
    } 
    bool operator!=(UClass* pPointer) 
    { 
     return _pRef->pObject != pPointer; 
    } 
    bool operator !(void) 
    { 
     return (_pRef->pObject == 0x0); 
    } 
    operator bool(void) 
    { 
     return (_pRef->pObject != 0x0); 
    } 
}; 
#endif 
+1

Не похоже, что вы нарушаете правила, но все равно оставите это здесь: [Что такое правила об использовании подчеркивания в идентификаторе C++?] (Http://stackoverflow.com/questions/228783/what -are-the-rules-about-use-an-underscore-in-ac-identifier) ​​ – user4581301

+0

да .. на протяжении многих лет я как бы начал разрабатывать свои собственные нотации .. не является стандартом C++ .. но есть крест язык, который можно использовать ... поэтому я всегда использую одну и ту же нотацию, когда мне приходится менять языки в одном проекте .. (C#/javascript/SQL) .. он уменьшает нагрузку адаптации каждый раз, когда вы переходите. – CaldasGSM

+0

Соглашения об именах являются хорошими вещь. Я использую множество префиксов и суффиксов как мнемонику и подсказки. Беспокойство с подчеркиванием - вы можете случайно использовать имя, принадлежащее стандартной библиотечной реализации, и получить ошибки компилятора или действительно странные результаты выполнения. – user4581301

1
A object1; 
B object2(A); 

Можно ли это сделать с любым из умных указателей в станд :: памяти?

С помощью стандартных интеллектуальных указателей вы не получите глубокую семантику копирования. У вас будет либо мелкая семантика копии (с std :: shared_ptr), либо семантика перемещения (с помощью std :: unique_ptr). Однако ничто не мешает вам создать метод clone() в вашем классе, который возвращает интеллектуальный указатель. Таким образом, вы можете получить свою глубокую копию, когда вам это нужно, но при этом получаете выгоду от семантики владения, которая поставляется с интеллектуальными указателями.

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