テンプレートを使用せずにスマート ポインターの基本クラスを作成できるかどうか疑問に思っていました。
多くの実装を見てきましたが、すべてテンプレートを使用しています。たとえば、他のクラスの派生元である基本クラスにスマート ポインター ロジックを実装します。
テンプレートを使用せずにスマート ポインターの基本クラスを作成できるかどうか疑問に思っていました。
多くの実装を見てきましたが、すべてテンプレートを使用しています。たとえば、他のクラスの派生元である基本クラスにスマート ポインター ロジックを実装します。
問題は、ポインター メンバーのクラスです。
C# のような言語では、他のすべてのクラスが派生する「オブジェクト」クラスがあるため、可能です。その場合、型の安全性が失われます。
ただし、C++ ではそのようなことはありません。2 つの選択肢があります。
したがって、最善の方法はテンプレートを使用することです。
ところで、テンプレートのアイデアは非常に優れているため、C# はいくつかのバージョンの後にそれを使用するようになりました。
なぜかわからない
#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();
}
}
スマート ポインター クラスをリソースの特定のデータ型のみのリソース管理クラスとして機能させたい場合は、テンプレートは必要ありません。
一般的なリソース マネージャー クラスを作成する場合は、テンプレート クラスが必要です。
このアプローチの問題点は、メソッドを追加できないことです。はい、必要に応じて継承を使用してスマート ポインターを作成できますが、結果はかなり制限されます。この場合、継承は最善の解決策ではありません。動的ポリモーフィズムが最善の解決策になることはめったにありませんが、これは別の、より大きな議論です (決してそうではないとは言っていないことに注意してください)。