unique_ptr

概要:スマートポインター
  • noncopyable(コピー禁止)

警告

既に unique_ptr で管理されたポインターを引数にすると破綻する

1
2
3
4
{
  unique_ptr< int > c(new int);
  unique_ptr< int > c2(c.get());
} // <- 2回deleteが実行されてしまう

実装例

概要:
  • STLの unique_ptr (もしくは boost )が使える環境ならそれを使う。
  • テンプレートの部分特殊化が使える環境の場合、unique_ptr を加工して使用する。
  • テンプレートの部分特殊化が使えない環境の場合、scoped_ptr 及び scoped_array を加工して使用する。

unique_ptr

概要:配列の場合、テンプレート引数に [] を含める
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
template< class TType >
struct default_delete
{
    void operator()(TType* P_) const { delete P_; }
};
template< class TType >
struct default_delete<TType[]>
{
    void operator()(TType* P_) const { delete[] P_; }
};

template<
    class TType,
    class TDeleter = default_delete<TType>
>
class unique_ptr //< noncopyable
{
    template<class T> struct remove_extent { typedef T type; };
    template<class T> struct remove_extent<T[]> { typedef T type; };
public:
    typedef typename remove_extent<TType>::type element_type;
    typedef TDeleter deleter_type;
    typedef element_type* pointer;

    explicit unique_ptr(pointer P_ = pointer(), const deleter_type& D_ = deleter_type())
        : managed_pointer_(P_), managed_deleter_(D_) {}
    ~unique_ptr()
    {
        if (this->managed_pointer_ != pointer()) {
            this->get_deleter()(this->managed_pointer_);
        }
    }
    pointer release()
    {
        pointer R_ = this->managed_pointer_;
        this->managed_pointer_ = pointer();
        return R_;
    }
    void reset(pointer P_ = pointer())
    {
        pointer old = this->managed_pointer_;
        this->managed_pointer_ = P_;
        if (old != pointer()) {
            this->get_deleter()(old);
        }
    }
    pointer get() const { return (this->managed_pointer_); }
    element_type& operator*() const { return (*this->managed_pointer_); }
    pointer operator->() const { return &**this; }
    deleter_type& get_deleter() { return managed_deleter_; }
    const deleter_type& get_deleter() const { return managed_deleter_; }
    explicit operator bool() const { return (this->managed_pointer_ != pointer()); }
private:
    unique_ptr(const unique_ptr&); // = delete; //< noncopyable
    unique_ptr& operator=(const unique_ptr&); // = delete; //< noncopyable

    pointer managed_pointer_;
    deleter_type managed_deleter_;
};

scoped_ptr & scoped_array

概要:
テンプレートの部分特殊化を使用しない版 (Non Partial template specialization)
配列の場合、テンプレート引数に [] を含めずに scoped_array を使用する
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
template< class TType >
struct scoped_default_delete
{
    void operator()(TType* P_) const { delete P_; }
};
template< class TType >
struct scoped_default_delete_array
{
    void operator()(TType* P_) const { delete[] P_; }
};

template< class TType, class TDeleter >
class scoped_ptr_base //< noncopyable
{
public:
    typedef TType element_type;
    typedef TDeleter deleter_type;
    typedef element_type* pointer;

    pointer release()
    {
        pointer R_ = this->managed_pointer_;
        this->managed_pointer_ = pointer();
        return R_;
    }
    void reset(pointer P_ = pointer())
    {
        pointer old = this->managed_pointer_;
        this->managed_pointer_ = P_;
        if (old != pointer()) {
            this->get_deleter()(old);
        }
    }
    pointer get() const { return (this->managed_pointer_); }
    element_type& operator*() const { return (*this->managed_pointer_); }
    pointer operator->() const { return &**this; }
    deleter_type& get_deleter() { return managed_deleter_; }
    const deleter_type& get_deleter() const { return managed_deleter_; }
    explicit operator bool() const { return (this->managed_pointer_ != pointer()); }
protected:
    scoped_ptr_base(pointer P_, const deleter_type& D_)
        : managed_pointer_(P_), managed_deleter_(D_) {}
    ~scoped_ptr_base() {}
    void destroy()
    {
        if (this->managed_pointer_ != pointer()) {
            this->get_deleter()(this->managed_pointer_);
        }
    }
private:
    scoped_ptr_base(const scoped_ptr_base&); // = delete; //< noncopyable
    scoped_ptr_base& operator=(const scoped_ptr_base&); // = delete; //< noncopyable

    pointer managed_pointer_;
    deleter_type managed_deleter_;
};

template< class TType, class TDeleter = scoped_default_delete<TType> >
class scoped_ptr : public scoped_ptr_base< TType, TDeleter > //< noncopyable
{
public:
    explicit scoped_ptr(pointer P_ = pointer(), const deleter_type& D_ = deleter_type())
        : scoped_ptr_base(P_, D_) {}
    ~scoped_ptr() { destroy(); }
};

template< class TType, class TDeleter = scoped_default_delete_array<TType> >
class scoped_array : public scoped_ptr_base< TType, TDeleter > //< noncopyable
{
public:
    explicit scoped_array(pointer P_ = pointer(), const deleter_type& D_ = deleter_type())
        : scoped_ptr_base(P_, D_) {}
    ~scoped_array() { destroy(); }
};

使用例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>

namespace poor_lib {
#include "poor_lib/unique_ptr.hpp"
#include "poor_lib/scoped_ptr.hpp"
}


class TestClass
{
public:
    TestClass(){}
    const char* const toString() { return "TestClass::toString()"; }
    void destroy() { delete this; }
private:
    ~TestClass(){}
};

struct TestClassDeleter
{
    void operator()(TestClass* P_) const
    {
        std::cout << "TestClass::destroy" << std::endl;
        P_->destroy();
    }
};
// namespace std
// {
//  template<>
//  struct default_delete<TestClass>
//  {
//      void operator()(TestClass* P_) const
//      {
//          P_->destroy();
//      }
//  };
// };


int main(int argc, char* argv[])
{
    {   // unique_ptr
        poor_lib::unique_ptr< int > one(new int);
        poor_lib::unique_ptr< int[] > ary(new int[256]);
    }
    {   // scoped_ptr, scoped_array
        poor_lib::scoped_ptr< int > one(new int);
        poor_lib::scoped_array< int > ary(new int[256]);
    }
    {   // Deleter指定でクラスを格納する場合(scoped_ptrも同様)
        const poor_lib::unique_ptr< TestClass, TestClassDeleter > c(new TestClass);
        std::cout << c->toString() << std::endl;
        std::cout << (*c).toString() << std::endl;
    }
    {   // 配列格納時(scoped_arrayは[]無し)
        poor_lib::unique_ptr< char[] > buffer(new char[256]);
        const char* F_ = "test string";
        char* O_ = buffer.get();
        while (*F_ != '\0') {
            *O_++ = *F_++;
        }
        *O_ = *F_;
        std::cout << buffer.get() << std::endl;
    }
    return 0;
}