summaryrefslogtreecommitdiff
path: root/src/libical/icptrholder_cxx.h
blob: 95b65e5c2b91b9d05410d62b43e5562f2b8cad2a (plain)
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/**
 * @file    icptrholder_cxx.h
 * @author  wyau (08/29/02)
 * @brief   C++ template classes for managing C++ pointers returned by
 *          VComponent::get_..._component, VComponent::get_..._property,
 *          ICalProperty::get_..._value.
 *
 * @remarks VComponent::get... functions returns a C++ object that wraps the
 * libical implementation. It is important to note that the wrapped
 * implementation still belongs to the original component. To stop memory leak,
 * caller must delete the pointer. However, the destructor will call the
 * appropriate free function. eg. ~VComponent calls icalcomponent_free(imp).
 *
 * As stated previously, imp still belongs to the original component. To avoid
 * freeing the wrapped "imp", caller must set the "imp" to null before deleting
 * the pointer.
 *
 * The template class relieves the burden of memory management when used as a
 * stack based object.  The class holds a pointer to the C++ Wrapper.
 * The destructor set the imp to null before deleting the pointer.
 *
 * Each C++ Wrapper instantiates a template class in its corresponding .h file.
 *
 * Usage example:
 *   VComponentTmpPtr p;// VComponentTmpPtr is an instantiation of this template
 *   for (p=component.get_first_component; p!= 0; p=component.get_next_component) {
 *
 * SPDX-FileCopyrightText: 2001, Critical Path

 SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0

 */

#ifndef ICPTRHOLDER_CXX_H
#define ICPTRHOLDER_CXX_H

#include <cassert>

template < class T > class ICPointerHolder
{
public:
    ICPointerHolder()
        : ptr(0)
    {
    }

    ICPointerHolder(T *p)
        : ptr(p)
    {
    }

    // copy constructor to support assignment
    ICPointerHolder(const ICPointerHolder &ip)
        : ptr(ip.ptr)
    {
        // We need to transfer ownership of ptr to this object by setting
        // ip's ptr to null. Otherwise, ptr will de deleted twice.
        // const ugliness requires us to do the const_cast.
        ICPointerHolder *ipp = const_cast < ICPointerHolder * >(&ip);

        ipp->ptr = 0;
    };

    ~ICPointerHolder()
    {
        release();
    }

    ICPointerHolder &operator=(T *p)
    {
        this->release();
        ptr = p;
        return *this;
    }

    ICPointerHolder &operator=(ICPointerHolder &p)
    {
        this->release();
        ptr = p.ptr;    // this transfer ownership of the pointer
        p.ptr = 0;      // set it to null so the pointer won't get delete twice.
        return *this;
    }

    bool operator!=(T *p)
    {
        return (ptr != p);
    }

    bool operator==(T *p)
    {
        return (ptr == p);
    }

    operator  T *() const
    {
        return ptr;
    }

    T *operator->() const
    {
        icalassert(ptr);
        return ptr;
    }

    T &operator*()
    {
        icalassert(ptr);
        return *ptr;
    }

private:
    void release()
    {
        if (ptr != 0) {
            ptr->detach();
            delete ptr;

            ptr = 0;
        }
    }

    T *ptr;
};

#endif