Coverage Report

Created: 2025-06-13 06:23

/src/brpc/src/butil/memory/ref_counted.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
#ifndef BUTIL_MEMORY_REF_COUNTED_H_
6
#define BUTIL_MEMORY_REF_COUNTED_H_
7
8
#include <cassert>
9
10
#include "butil/atomic_ref_count.h"
11
#include "butil/base_export.h"
12
#include "butil/compiler_specific.h"
13
#ifndef NDEBUG
14
#include "butil/logging.h"
15
#endif
16
#include "butil/threading/thread_collision_warner.h"
17
18
namespace butil {
19
20
namespace subtle {
21
22
class BUTIL_EXPORT RefCountedBase {
23
 public:
24
0
  bool HasOneRef() const { return ref_count_ == 1; }
25
26
 protected:
27
  RefCountedBase()
28
      : ref_count_(0)
29
      , in_dtor_(false)
30
0
      {
31
0
  }
32
33
0
  ~RefCountedBase() {
34
0
  #ifndef NDEBUG
35
0
    DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
36
0
  #endif
37
0
  }
38
39
40
0
  void AddRef() const {
41
0
    // TODO(maruel): Add back once it doesn't assert 500 times/sec.
42
0
    // Current thread books the critical section "AddRelease"
43
0
    // without release it.
44
0
    // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
45
0
  #ifndef NDEBUG
46
0
    DCHECK(!in_dtor_);
47
0
  #endif
48
0
    ++ref_count_;
49
0
  }
50
51
  // Returns true if the object should self-delete.
52
0
  bool Release() const {
53
0
    // TODO(maruel): Add back once it doesn't assert 500 times/sec.
54
0
    // Current thread books the critical section "AddRelease"
55
0
    // without release it.
56
0
    // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
57
0
  #ifndef NDEBUG
58
0
    DCHECK(!in_dtor_);
59
0
  #endif
60
0
    if (--ref_count_ == 0) {
61
0
  #ifndef NDEBUG
62
0
      in_dtor_ = true;
63
0
  #endif
64
0
      return true;
65
0
    }
66
0
    return false;
67
0
  }
68
69
 private:
70
  mutable int ref_count_;
71
#if defined(__clang__)
72
  mutable bool ALLOW_UNUSED  in_dtor_;
73
#else
74
  mutable bool in_dtor_;
75
#endif
76
  DFAKE_MUTEX(add_release_);
77
78
  DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
79
};
80
81
class BUTIL_EXPORT RefCountedThreadSafeBase {
82
 public:
83
  bool HasOneRef() const;
84
85
 protected:
86
  RefCountedThreadSafeBase();
87
  ~RefCountedThreadSafeBase();
88
89
  void AddRef() const;
90
91
  // Returns true if the object should self-delete.
92
  bool Release() const;
93
94
 private:
95
  mutable AtomicRefCount ref_count_;
96
#if defined(__clang__)
97
  mutable bool ALLOW_UNUSED  in_dtor_;
98
#else
99
  mutable bool in_dtor_;
100
#endif
101
102
  DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
103
};
104
105
}  // namespace subtle
106
107
//
108
// A base class for reference counted classes.  Otherwise, known as a cheap
109
// knock-off of WebKit's RefCounted<T> class.  To use this guy just extend your
110
// class from it like so:
111
//
112
//   class MyFoo : public butil::RefCounted<MyFoo> {
113
//    ...
114
//    private:
115
//     friend class butil::RefCounted<MyFoo>;
116
//     ~MyFoo();
117
//   };
118
//
119
// You should always make your destructor private, to avoid any code deleting
120
// the object accidently while there are references to it.
121
template <class T>
122
class RefCounted : public subtle::RefCountedBase {
123
 public:
124
  RefCounted() {}
125
126
  void AddRef() const {
127
    subtle::RefCountedBase::AddRef();
128
  }
129
130
  void Release() const {
131
    if (subtle::RefCountedBase::Release()) {
132
      delete static_cast<const T*>(this);
133
    }
134
  }
135
136
 protected:
137
  ~RefCounted() {}
138
139
 private:
140
  DISALLOW_COPY_AND_ASSIGN(RefCounted);
141
};
142
143
// Forward declaration.
144
template <class T, typename Traits> class RefCountedThreadSafe;
145
146
// Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
147
// count reaches 0.  Overload to delete it on a different thread etc.
148
template<typename T>
149
struct DefaultRefCountedThreadSafeTraits {
150
0
  static void Destruct(const T* x) {
151
    // Delete through RefCountedThreadSafe to make child classes only need to be
152
    // friend with RefCountedThreadSafe instead of this struct, which is an
153
    // implementation detail.
154
0
    RefCountedThreadSafe<T,
155
0
                         DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
156
0
  }
157
};
158
159
//
160
// A thread-safe variant of RefCounted<T>
161
//
162
//   class MyFoo : public butil::RefCountedThreadSafe<MyFoo> {
163
//    ...
164
//   };
165
//
166
// If you're using the default trait, then you should add compile time
167
// asserts that no one else is deleting your object.  i.e.
168
//    private:
169
//     friend class butil::RefCountedThreadSafe<MyFoo>;
170
//     ~MyFoo();
171
template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
172
class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
173
 public:
174
0
  RefCountedThreadSafe() {}
175
176
0
  void AddRef() const {
177
0
    subtle::RefCountedThreadSafeBase::AddRef();
178
0
  }
179
180
0
  void Release() const {
181
0
    if (subtle::RefCountedThreadSafeBase::Release()) {
182
0
      Traits::Destruct(static_cast<const T*>(this));
183
0
    }
184
0
  }
185
186
 protected:
187
  ~RefCountedThreadSafe() {}
188
189
 private:
190
  friend struct DefaultRefCountedThreadSafeTraits<T>;
191
0
  static void DeleteInternal(const T* x) { delete x; }
192
193
  DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
194
};
195
196
//
197
// A thread-safe wrapper for some piece of data so we can place other
198
// things in scoped_refptrs<>.
199
//
200
template<typename T>
201
class RefCountedData
202
    : public butil::RefCountedThreadSafe< butil::RefCountedData<T> > {
203
 public:
204
  RefCountedData() : data() {}
205
  RefCountedData(const T& in_value) : data(in_value) {}
206
207
  T data;
208
209
 private:
210
  friend class butil::RefCountedThreadSafe<butil::RefCountedData<T> >;
211
  ~RefCountedData() {}
212
};
213
214
}  // namespace butil
215
216
//
217
// A smart pointer class for reference counted objects.  Use this class instead
218
// of calling AddRef and Release manually on a reference counted object to
219
// avoid common memory leaks caused by forgetting to Release an object
220
// reference.  Sample usage:
221
//
222
//   class MyFoo : public RefCounted<MyFoo> {
223
//    ...
224
//   };
225
//
226
//   void some_function() {
227
//     scoped_refptr<MyFoo> foo = new MyFoo();
228
//     foo->Method(param);
229
//     // |foo| is released when this function returns
230
//   }
231
//
232
//   void some_other_function() {
233
//     scoped_refptr<MyFoo> foo = new MyFoo();
234
//     ...
235
//     foo = NULL;  // explicitly releases |foo|
236
//     ...
237
//     if (foo)
238
//       foo->Method(param);
239
//   }
240
//
241
// The above examples show how scoped_refptr<T> acts like a pointer to T.
242
// Given two scoped_refptr<T> classes, it is also possible to exchange
243
// references between the two objects, like so:
244
//
245
//   {
246
//     scoped_refptr<MyFoo> a = new MyFoo();
247
//     scoped_refptr<MyFoo> b;
248
//
249
//     b.swap(a);
250
//     // now, |b| references the MyFoo object, and |a| references NULL.
251
//   }
252
//
253
// To make both |a| and |b| in the above example reference the same MyFoo
254
// object, simply use the assignment operator:
255
//
256
//   {
257
//     scoped_refptr<MyFoo> a = new MyFoo();
258
//     scoped_refptr<MyFoo> b;
259
//
260
//     b = a;
261
//     // now, |a| and |b| each own a reference to the same MyFoo object.
262
//   }
263
//
264
template <class T>
265
class scoped_refptr {
266
 public:
267
  typedef T element_type;
268
269
  scoped_refptr() : ptr_(NULL) {
270
  }
271
272
0
  scoped_refptr(T* p) : ptr_(p) {
273
0
    if (ptr_)
274
0
      ptr_->AddRef();
275
0
  }
276
277
  scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
278
    if (ptr_)
279
      ptr_->AddRef();
280
  }
281
282
  template <typename U>
283
  scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
284
    if (ptr_)
285
      ptr_->AddRef();
286
  }
287
288
  scoped_refptr(scoped_refptr<T>&& r) noexcept {
289
    ptr_ = r.ptr_;
290
    r.ptr_ = nullptr;
291
  }
292
293
  template <typename U>
294
  scoped_refptr(scoped_refptr<U>&& r) noexcept {
295
    ptr_ = r.ptr_;
296
    r.ptr_ = nullptr;
297
  }
298
299
0
  ~scoped_refptr() {
300
0
    if (ptr_)
301
0
      ptr_->Release();
302
0
  }
303
304
  T* get() const { return ptr_; }
305
306
  // Allow scoped_refptr<C> to be used in boolean expression
307
  // and comparison operations.
308
  operator T*() const { return ptr_; }
309
310
0
  T* operator->() const {
311
0
    assert(ptr_ != NULL);
312
0
    return ptr_;
313
0
  }
314
315
  scoped_refptr<T>& operator=(T* p) {
316
    // AddRef first so that self assignment should work
317
    if (p)
318
      p->AddRef();
319
    T* old_ptr = ptr_;
320
    ptr_ = p;
321
    if (old_ptr)
322
      old_ptr->Release();
323
    return *this;
324
  }
325
326
  scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
327
    return *this = r.ptr_;
328
  }
329
330
  template <typename U>
331
  scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
332
    return *this = r.get();
333
  }
334
335
  void swap(T** pp) {
336
    T* p = ptr_;
337
    ptr_ = *pp;
338
    *pp = p;
339
  }
340
341
  void swap(scoped_refptr<T>& r) {
342
    swap(&r.ptr_);
343
  }
344
345
  // Release ownership of ptr_, keeping its reference counter unchanged.
346
  T* release() WARN_UNUSED_RESULT {
347
      T* saved_ptr = NULL;
348
      swap(&saved_ptr);
349
      return saved_ptr;
350
  }
351
352
 protected:
353
  T* ptr_;
354
};
355
356
// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without
357
// having to retype all the template arguments
358
template <typename T>
359
scoped_refptr<T> make_scoped_refptr(T* t) {
360
  return scoped_refptr<T>(t);
361
}
362
363
#endif  // BUTIL_MEMORY_REF_COUNTED_H_