Smart Ptr - intrusive

发布时间 2023-07-28 14:19:26作者: fndefbwefsowpvqfx

intrusive_ref_counter

template< typename DerivedT, typename CounterPolicyT >
class intrusive_ref_counter


struct thread_unsafe_counter
struct thread_safe_counter

The intrusive_ref_counter class template implements a reference counter for a derived user’s class that is intended to be used with intrusive_ptr. The base class has associated intrusive_ptr_add_ref and intrusive_ptr_release functions which modify the reference counter as needed and destroy the user’s object when the counter drops to zero.

The class template is parameterized on Derived and CounterPolicy parameters. The first parameter is the user’s class that derives from intrusive_ref_counter. This type is needed in order to destroy the object correctly when there are no references to it left.

The second parameter is a policy that defines the nature of the reference counter. The library provides two such policies: thread_unsafe_counter and thread_safe_counter. The former instructs the intrusive_ref_counter base class to use a counter only suitable for a single-threaded use. Pointers to a single object that uses this kind of reference counter must not be used in different threads. The latter policy makes the reference counter thread-safe, unless the target platform doesn’t support threading. Since in modern systems support for threading is common, the default counter policy is thread_safe_counter.

intrusive_ptr

The intrusive_ptr class template stores a pointer to an object with an embedded reference count. Every new intrusive_ptr instance increments the reference count by using an unqualified call to the function intrusive_ptr_add_ref, passing it the pointer as an argument. Similarly, when an intrusive_ptr is destroyed, it calls intrusive_ptr_release; this function is responsible for destroying the object when its reference count drops to zero. The user is expected to provide suitable definitions of these two functions. On compilers that support argument-dependent lookup, intrusive_ptr_add_ref and intrusive_ptr_release should be defined in the namespace that corresponds to their parameter; otherwise, the definitions need to go in namespace boost. The library provides a helper base class template intrusive_ref_counter which may help adding support for intrusive_ptr to user types.

The class template is parameterized on T, the type of the object pointed to. intrusive_ptr<T> can be implicitly converted to intrusive_ptr<U> whenever T* can be implicitly converted to U*.

The main reasons to use intrusive_ptr are:

  • Some existing frameworks or OSes provide objects with embedded reference counts;
  • The memory footprint of intrusive_ptr is the same as the corresponding raw pointer;
  • intrusive_ptr<T> can be constructed from an arbitrary raw pointer of type T*.

As a general rule, if it isn’t obvious whether intrusive_ptr better fits your needs than shared_ptr, try a shared_ptr based design first.

#include <boost/intrusive_ptr.hpp>
#include <iostream>

class MyClass {
 public:
  MyClass() : ref_count_(0) {}
  friend void intrusive_ptr_add_ref(MyClass* p) { ++p->ref_count_; }
  friend void intrusive_ptr_release(MyClass* p) {
    if (--p->ref_count_ == 0) delete p;
  }
  void Print() { std::cout << "Hello, world!" << std::endl; }
 private:
  int ref_count_;
};
int main() {
  boost::intrusive_ptr<MyClass> ptr(new MyClass());
  ptr->Print();
  return 0;
}
#include <boost/intrusive_ptr.hpp>
#include <atlbase.h>
#include <iostream>

void intrusive_ptr_add_ref(IDispatch *p) { p->AddRef(); }
void intrusive_ptr_release(IDispatch *p) { p->Release(); }

void check_windows_folder()
{
  CLSID clsid;
  CLSIDFromProgID(CComBSTR{"Scripting.FileSystemObject"}, &clsid);
  void *p;
  CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, __uuidof(IDispatch), &p);
  boost::intrusive_ptr<IDispatch> disp{static_cast<IDispatch*>(p), false};
  CComDispatchDriver dd{disp.get()};
  CComVariant arg{"C:\\Windows"};
  CComVariant ret{false};
  dd.Invoke1(CComBSTR{"FolderExists"}, &arg, &ret);
  std::cout << std::boolalpha << (ret.boolVal != 0) << '\n';
}

int main()
{
  CoInitialize(0);
  check_windows_folder();
  CoUninitialize();
}
#include <boost/intrusive_ptr.hpp>
#include <boost/smart_ptr/intrusive_ref_counter.hpp>

class YourClass : public boost::intrusive_ref_counter<YourClass,boost::thread_unsafe_counter> {

};

boost::intrusive_ptr<YourClass> myPtr;