📄 shared_ptr.h
字号:
/* Copyright (C) 2004 Chris VineThis program is distributed under the General Public Licence, version 2.For particulars of this and relevant disclaimers see the fileCOPYING distributed with the source files.*/#ifndef SHARED_PTR_H#define SHARED_PTR_H#include <glibmm/thread.h>template <class T> class Shared_ptr { struct { unsigned int* ref_count_p; T* obj_p; } ref_items; void unreference(void) { --*ref_items.ref_count_p; if (*ref_items.ref_count_p == 0) { delete ref_items.obj_p; // if this is NULL it is still safe to apply delete to it delete ref_items.ref_count_p; } } void reference(void) { ++*ref_items.ref_count_p; }public: // constructor of first Shared_ptr holding the referenced object explicit Shared_ptr(T* ptr = 0) { ref_items.ref_count_p = new unsigned int(1); ref_items.obj_p = ptr; } // copy constructors Shared_ptr(const Shared_ptr& sh_ptr) throw() { ref_items = sh_ptr.ref_items; reference(); } template <class U> friend class Shared_ptr; template <class U> Shared_ptr(const Shared_ptr<U>& sh_ptr) throw() { // because we are allowing an implicit cast from derived to // base class referenced object, we need to assign from each // member of sh_ptr.ref_items separately ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p; ref_items.obj_p = sh_ptr.ref_items.obj_p; reference(); } // copy assignment Shared_ptr& operator=(const Shared_ptr& sh_ptr) throw() { // check whether we are already referencing this object - // if so make this a null op. This will also deal with // self-assignment if (ref_items.obj_p != sh_ptr.ref_items.obj_p) { // first unreference any object referenced by this shared pointer unreference(); // now inherit the ref_items structure from the assigning // shared pointer and reference the object it references ref_items = sh_ptr.ref_items; reference(); } return *this; } template <class U> Shared_ptr& operator=(const Shared_ptr<U>& sh_ptr) throw() { return operator=(Shared_ptr(sh_ptr)); } T* get(void) const throw() {return ref_items.obj_p;} T& operator*(void) const throw() {return *ref_items.obj_p;} T* operator->(void) const throw() {return ref_items.obj_p;} unsigned int get_refcount(void) const throw() {return *ref_items.ref_count_p;} // destructor ~Shared_ptr(void) throw() {unreference();}};/* Class Shared_lock_ptr is a version of the shared pointer class which includes mutex locking so that it can be accessed in multiple threads. Note that only the reference count is protected by a mutex, so this is thread safe in the sense in which a raw pointer is thread safe. A shared pointer accessed in one thread referencing a particular object is thread safe as against another shared pointer accessing the same object in a different thread. It is thus suitable for use in different Std C++ containers which exist in different threads but which contain shared objects by reference. But: 1. If the referenced object is to be modified in one thread and read or modified in another thread an appropriate mutex for the referenced object is required (unless that referenced object does its own locking). 2. If the same instance of shared pointer is to be modified in one thread (by assigning to the pointer so that it references a different object), and copied (assigned from or used as the argument of a copy constructor) or modified in another thread, a mutex for that instance of shared pointer is required. 3. Objects referenced by shared pointers which are objects for which POSIX provides no guarantees (in the main, those which are not built-in types), such as strings and similar containers, may not support concurrent reads in different threads. That depends on the library implementation concerned. If that is the case, a mutex for the referenced object will also be required when reading any given instance of such an object in more than one thread by dereferencing any shared pointers referencing it (and indeed, when not using shared pointers at all).*/template <class T> class Shared_lock_ptr { struct Ref_items { Glib::Mutex* mutex_p; unsigned int* ref_count_p; T* obj_p; } ref_items; void unreference(void) { // the mutex in ref_items will have been locked before we got here // so we do not need to lock it in this method. The call to this method // which results in the deletion of the referenced object (that is, which // cause the reference count to reach 0) will have been made in the // destructor of this shared pointer instance so we need to unlock() the // mutex and then delete it --*ref_items.ref_count_p; if (*ref_items.ref_count_p == 0) { delete ref_items.obj_p; // if this is NULL it is still safe to apply delete to it delete ref_items.ref_count_p; // the referenced object has now been destroyed // it is safe to unlock the mutex here and then // to delete the mutex - there can be no further call // to this method with respect to that object ref_items.mutex_p->unlock(); delete ref_items.mutex_p; // set ref_items.mutex_p to NULL so that the destructor and operator=() // know not to try and unlock the mutex where we called ref_itemserence() in the // destructor or operator=() ref_items.mutex_p = 0; } } void reference(void) { ++*ref_items.ref_count_p; }public: // constructor of first Shared_lock_ptr holding the referenced object explicit Shared_lock_ptr(T* ptr = 0) { ref_items.mutex_p = new Glib::Mutex; // make this constructor exception safe try { ref_items.ref_count_p = new unsigned int(1); } catch (...) { delete ref_items.mutex_p; throw; } ref_items.obj_p = ptr; } // copy constructors Shared_lock_ptr(const Shared_lock_ptr& sh_ptr) throw() { ref_items = sh_ptr.ref_items; Glib::Mutex::Lock lock(*ref_items.mutex_p); reference(); } template <class U> friend class Shared_lock_ptr; template <class U> Shared_lock_ptr(const Shared_lock_ptr<U>& sh_ptr) throw() { // because we are allowing an implicit cast from derived to // base class referenced object, we need to assign from each // member of sh_ptr.ref_items separately ref_items.mutex_p = sh_ptr.ref_items.mutex_p; ref_items.obj_p = sh_ptr.ref_items.obj_p; ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p; Glib::Mutex::Lock lock(*ref_items.mutex_p); reference(); } // copy assignment Shared_lock_ptr& operator=(const Shared_lock_ptr& sh_ptr) throw() { // check whether we are already referencing this object - // if so make this a null op. This will also deal with // self-assignment if (ref_items.obj_p != sh_ptr.ref_items.obj_p) { // first unreference any object referenced by this shared pointer ref_items.mutex_p->lock(); unreference(); if (ref_items.mutex_p) ref_items.mutex_p->unlock(); // now inherit the ref_items structure from the assigning // shared pointer and reference the object it references ref_items = sh_ptr.ref_items; Glib::Mutex::Lock lock(*ref_items.mutex_p); reference(); } return *this; } template <class U> Shared_lock_ptr& operator=(const Shared_lock_ptr<U>& sh_ptr) throw() { return operator=(Shared_lock_ptr(sh_ptr)); } T* get(void) const throw() {return ref_items.obj_p;} T& operator*(void) const throw() {return *ref_items.obj_p;} T* operator->(void) const throw() {return ref_items.obj_p;} unsigned int get_refcount(void) const throw() { Glib::Mutex::Lock lock(*ref_items.mutex_p); return *ref_items.ref_count_p; } // destructor ~Shared_lock_ptr(void) throw() { ref_items.mutex_p->lock(); unreference(); // if unreference() has deleted the referenced object because // this is the last shared pointer referencing it, we do not // want to unlock here as the mutex will have been destroyed // also if (ref_items.mutex_p) ref_items.mutex_p->unlock(); }};#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -