0

Мне было интересно, можно ли создать базовый признак умного указателя без использования шаблона?Возможно ли создать простой умный указатель baseclass без шаблонов?

Я видел ряд реализаций, но все используют tempalates. Например, реализация логики интеллектуального указателя в базовом классе, из которого производятся другие классы.

+0

Можете ли вы дать какой-то пример того, что вы хотите? Вам нужен какой-то «беспричинный» «shared_ptr», с которым вы не сможете получить доступ к содержащимся данным, но которые вы могли бы удерживать в течение длительного времени, чтобы отложить уничтожение? –

+1

Почему вы хотите избежать шаблонов? Описывая свои цели (умный указатель, который работает в ситуации X), а не конкретная попытка решения (избегать шаблонов), может обеспечить лучшее решение. – jalf

+0

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

ответ

2

Проблема заключается в классе вашего указателя.

В таких языках, как C#, возможно, потому что существует «объект» класс, из которого вытекает каждый другой класс. В этом случае вы потеряете безопасность типа.

Однако, в C++ вы не имеете такую ​​вещь, которая оставляет вас с 2-х вариантов:

  1. Использование пустоту * и reinterpet_cast - очень некрасиво, на самом деле не безопасно из-за безопасности типа ,
  2. Написание тонн перегрузок для вашего класса - для каждого класса. Это невозможно, потому что он не будет работать с новыми классами.

Таким образом, лучший способ - использовать шаблоны.
Кстати, идея шаблона настолько хороша, что C# начал использовать его после некоторой версии.

+0

Не достаточно ли писать перегрузки для базового слоя? – KaiserJohaan

+1

@ KaiserJohaan, базовый класс чего? –

0

Если вы хотите, чтобы ваш класс умных указателей выступал в качестве класса управления ресурсами только для определенного типа данных, то вам не нужен шаблон.

Если вы планируете писать общий класс менеджера ресурсов, вам нужен класс шаблона.

+2

И причина для downvote? –

1

Проблема с использованием этого подхода заключается в том, что вы не можете добавлять методы. Да, вы можете использовать наследование для создания интеллектуальных указателей, если хотите, но результат будет весьма ограниченным. В этом случае наследование составляет не лучшее решение. Динамический полиморфизм редко является лучшим решением, но это другое и гораздо более широкое обсуждение (обратите внимание, что я не сказал этого никогда is).

1

Я не знаю, почему

#include <iostream> 

class void_scoped_ptr { 
public: 
    virtual ~void_scoped_ptr() = 0; 
    void operator=(void_scoped_ptr const&) = delete; 

    explicit operator bool() const { return ptr != 0; } 

protected: 
    void_scoped_ptr(void* p) : ptr(p) {}; 

    void* ptr; 
}; 

void_scoped_ptr::~void_scoped_ptr() {} 

#define MAKE_DERIVED_SCOPED_BASE(T, NAME, DELETE, DEREF)     \ 
class NAME : void_scoped_ptr {            \ 
public:                  \ 
    typedef T element_type;             \ 
    typedef element_type* ptr_type;           \ 
    typedef element_type const* const_ptr_type;        \ 
                      \ 
    NAME(ptr_type p) : void_scoped_ptr(p) {}         \ 
    ~ NAME() { DELETE cast(); }            \ 
    void reset(ptr_type p) {             \ 
    DELETE cast();               \ 
    ptr = p;                \ 
    }                   \ 
                      \ 
    DEREF                  \ 
    element_type& operator*() { return *cast(); }        \ 
    element_type const& operator*() const { return *cast(); }     \ 
                      \ 
protected:                 \ 
    ptr_type cast() { return static_cast<ptr_type>(ptr); }     \ 
    const_ptr_type cast() const { return static_cast<ptr_type>(ptr); }  \ 
} 

#define MAKE_DERIVED_SCOPED_PTR(T)           \ 
    MAKE_DERIVED_SCOPED_BASE(T, T ## _scoped_ptr, delete,      \ 
    ptr_type operator->() { return cast(); }        \ 
    const_ptr_type operator->() const { return cast(); }     \ 
) 
#define MAKE_DERIVED_SCOPED_ARRAY(T)          \ 
    MAKE_DERIVED_SCOPED_BASE(T, T ## _scoped_array, delete [],    \ 
    element_type& operator[](size_t i) { return cast()[i]; }    \ 
    element_type const& operator[](size_t i) const { return cast()[i]; } \ 
) 

struct TestClass { 
    TestClass() { std::cout << "construct\n"; } 
    ~TestClass() { std::cout << "destruct\n"; } 

    void f() { std::cout << "f()\n"; } 
}; 

typedef MAKE_DERIVED_SCOPED_PTR(TestClass) test_ptr; 
typedef MAKE_DERIVED_SCOPED_ARRAY(TestClass) test_array; 

int main() { 
    { 
    test_ptr p(new TestClass); 
    p->f(); 
    } 

    { 
    test_array a(new TestClass[3]); 
    a[2].f(); 
    } 
}