Protect intrusive_ptr and ComPtr from moving to itself
[openal-soft.git] / common / comptr.h
blob5984ebd914ea29c8174e8a79b2129773cc6a9924
1 #ifndef COMMON_COMPTR_H
2 #define COMMON_COMPTR_H
4 #include <cstddef>
5 #include <utility>
7 #include "opthelpers.h"
10 template<typename T>
11 class ComPtr {
12 T *mPtr{nullptr};
14 public:
15 ComPtr() noexcept = default;
16 ComPtr(const ComPtr &rhs) : mPtr{rhs.mPtr} { if(mPtr) mPtr->AddRef(); }
17 ComPtr(ComPtr&& rhs) noexcept : mPtr{rhs.mPtr} { rhs.mPtr = nullptr; }
18 ComPtr(std::nullptr_t) noexcept { }
19 explicit ComPtr(T *ptr) noexcept : mPtr{ptr} { }
20 ~ComPtr() { if(mPtr) mPtr->Release(); }
22 ComPtr& operator=(const ComPtr &rhs)
24 if(!rhs.mPtr)
26 if(mPtr)
27 mPtr->Release();
28 mPtr = nullptr;
30 else
32 rhs.mPtr->AddRef();
33 try {
34 if(mPtr)
35 mPtr->Release();
36 mPtr = rhs.mPtr;
38 catch(...) {
39 rhs.mPtr->Release();
40 throw;
43 return *this;
45 ComPtr& operator=(ComPtr&& rhs)
47 if(likely(&rhs != this))
49 if(mPtr)
50 mPtr->Release();
51 mPtr = rhs.mPtr;
52 rhs.mPtr = nullptr;
54 return *this;
57 explicit operator bool() const noexcept { return mPtr != nullptr; }
59 T& operator*() const noexcept { return *mPtr; }
60 T* operator->() const noexcept { return mPtr; }
61 T* get() const noexcept { return mPtr; }
62 T** getPtr() noexcept { return &mPtr; }
64 T* release() noexcept { return std::exchange(mPtr, nullptr); }
66 void swap(ComPtr &rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
67 void swap(ComPtr&& rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
70 #endif