我建议使用 Boost 侵入式智能指针。
还有一个来自 Scott Meyer(这里:http://www.aristeia.com/BookErrata/M29Source.html)的实现,发表在“More Effective C++”中
但是,如果它有帮助,我拉了一个简单的引用计数指针(对多态赋值的一些支持和自定义删除器)。 这个是非线程感知的。
注意:我记错了。多态分配是另一个项目的变体。我也有,但它不支持自定义删除器:) 如果有人感兴趣,请告诉我;当然,它带有单独的功能单元测试
它带有单元测试(例如检查著名的remove linked list node 排序错误)。所以你知道你得到了什么:)
/*
* counted_ptr - simple reference counted pointer.
*
* The is a non-intrusive implementation that allocates an additional
* int and pointer for every counted object.
*/
#ifndef COUNTED_PTR_H
#define COUNTED_PTR_H
#include <stdlib.h>
extern "C" bool mtx_unit_test_countedptr();
namespace MtxChess {
/* For ANSI-challenged compilers, you may want to #define
* NO_MEMBER_TEMPLATES or explicit */
template <class X>
struct FreeMallocPolicy
{
static void do_free(X* p) { if (p) ::free(p); p = 0; }
};
template <class X>
struct ScalarDeletePolicy
{
static void do_free(X* p) { if (p) delete p; p = 0; }
};
template <class X>
struct ArrayDeletePolicy
{
static void do_free(X* p) { if (p) delete[] p; p = 0; }
};
template <class X,class _P=ScalarDeletePolicy<X> > class counted_ptr
{
public:
typedef X element_type;
explicit counted_ptr(X* p = 0) // allocate a new counter
: itsCounter(0) {if (p) itsCounter = new counter(p);}
~counted_ptr()
{release();}
counted_ptr(const counted_ptr& r) throw()
{acquire(r.itsCounter);}
operator bool() const { return 0!=get(); }
void clear() { (*this) = counted_ptr<X>(0); }
counted_ptr& operator=(const counted_ptr& r)
{
if (this != &r) {
auto_release keep(itsCounter);
acquire(r.itsCounter);
}
return *this;
}
bool operator<(const counted_ptr& r) const
{
return get()<r.get();
}
bool operator==(const counted_ptr& r) const
{
return get()==r.get();
}
bool operator!=(const counted_ptr& r) const
{
return get()!=r.get();
}
#ifndef NO_MEMBER_TEMPLATES
// template <class Y> friend class counted_ptr<Y>;
template <class Y> counted_ptr(const counted_ptr<Y>& r) throw()
{acquire(r.itsCounter);}
template <class Y> counted_ptr& operator=(const counted_ptr<Y>& r)
{
if (this != &r) {
auto_release keep(itsCounter);
acquire(r.itsCounter);
}
return *this;
}
template <class Y> bool operator<(const counted_ptr<Y>& r) const
{
return get()<r.get();
}
template <class Y> bool operator==(const counted_ptr<Y>& r) const
{
return get()==r.get();
}
template <class Y> bool operator!=(const counted_ptr<Y>& r) const
{
return get()!=r.get();
}
#endif // NO_MEMBER_TEMPLATES
X& operator*() const throw() {return *itsCounter->ptr;}
X* operator->() const throw() {return itsCounter->ptr;}
X* get() const throw() {return itsCounter ? itsCounter->ptr : 0;}
bool unique() const throw()
{return (itsCounter ? itsCounter->count == 1 : true);}
private:
struct counter {
counter(X* p = 0, unsigned c = 1) : ptr(p), count(c) {}
X* ptr;
unsigned count;
}* itsCounter;
void acquire(counter* c) throw()
{
// increment the count
itsCounter = c;
if (c) ++c->count;
}
void release()
{
dorelease(itsCounter);
}
struct auto_release
{
auto_release(counter* c) : _c(c) {}
~auto_release() { dorelease(_c); }
counter* _c;
};
void static dorelease(counter* itsCounter)
{
// decrement the count, delete if it is 0
if (itsCounter) {
if (--itsCounter->count == 0) {
_P::do_free(itsCounter->ptr);
delete itsCounter;
}
itsCounter = 0;
}
}
};
} // EON
#endif // COUNTED_PTR_H
单元测试(独立编译)
/*
* counted_ptr (cpp) - simple reference counted pointer.
*
* The is a non-intrusive implementation that allocates an additional
* int and pointer for every counted object.
*/
#include "counted_ptr.hpp"
#include "internal.hpp"
#include <map>
#include <string>
namespace MtxChess {
namespace /*anon*/
{
// sensed events
typedef std::map<std::string, int> Events;
static Events constructions, destructions;
struct Trackable
{
Trackable(const std::string& id) : _id(id) { constructions[_id]++; }
~Trackable() { destructions[_id]++; }
const std::string _id;
};
typedef counted_ptr<Trackable> target_t;
bool testBehaviour()
{
static const counted_ptr<Trackable> Nil = target_t(0);
bool ok = true;
constructions.clear();
destructions.clear();
MTXASSERT_EQ(ok, 0ul, constructions.size());
MTXASSERT_EQ(ok, 0ul, destructions.size());
target_t a = target_t(new Trackable("aap"));
MTXASSERT_EQ(ok, 1ul, constructions.size());
MTXASSERT_EQ(ok, 1, constructions["aap"]);
MTXASSERT_EQ(ok, 0ul, destructions.size());
MTXASSERT_EQ(ok, 0, constructions["noot"]);
MTXASSERT_EQ(ok, 2ul, constructions.size());
MTXASSERT_EQ(ok, 0ul, destructions.size());
target_t hold;
{
target_t b = target_t(new Trackable("noot")),
c = target_t(new Trackable("mies")),
nil = Nil,
a2 = a;
MTXASSERT(ok, a2==a);
MTXASSERT(ok, nil!=a);
MTXASSERT_EQ(ok, 3ul, constructions.size());
MTXASSERT_EQ(ok, 1, constructions["aap"]);
MTXASSERT_EQ(ok, 1, constructions["noot"]);
MTXASSERT_EQ(ok, 1, constructions["mies"]);
MTXASSERT_EQ(ok, 0, constructions["broer"]);
MTXASSERT_EQ(ok, 4ul, constructions.size());
MTXASSERT_EQ(ok, 0ul, destructions.size());
hold = b;
}
MTXASSERT_EQ(ok, 1ul, destructions.size());
MTXASSERT_EQ(ok, 0, destructions["aap"]);
MTXASSERT_EQ(ok, 0, destructions["noot"]);
MTXASSERT_EQ(ok, 1, destructions["mies"]);
MTXASSERT_EQ(ok, 3ul, destructions.size());
hold = Nil;
MTXASSERT_EQ(ok, 3ul, destructions.size());
MTXASSERT_EQ(ok, 0, destructions["aap"]);
MTXASSERT_EQ(ok, 1, destructions["noot"]);
MTXASSERT_EQ(ok, 1, destructions["mies"]);
MTXASSERT_EQ(ok, 4ul, constructions.size());
// ok, enuf for now
return ok;
}
struct Linked : Trackable
{
Linked(const std::string&t):Trackable(t){}
counted_ptr<Linked> next;
};
bool testLinked()
{
bool ok = true;
constructions.clear();
destructions.clear();
MTXASSERT_EQ(ok, 0ul, constructions.size());
MTXASSERT_EQ(ok, 0ul, destructions.size());
counted_ptr<Linked> node(new Linked("parent"));
MTXASSERT(ok, node.get());
node->next = counted_ptr<Linked>(new Linked("child"));
MTXASSERT_EQ(ok, 2ul, constructions.size());
MTXASSERT_EQ(ok, 0ul, destructions.size());
node = node->next;
MTXASSERT(ok, node.get());
MTXASSERT_EQ(ok, 2ul, constructions.size());
MTXASSERT_EQ(ok, 1ul, destructions.size());
node = node->next;
MTXASSERT(ok,!node.get());
MTXASSERT_EQ(ok, 2ul, constructions.size());
MTXASSERT_EQ(ok, 2ul, destructions.size());
return ok;
}
}
} // EON
int main()
{
using namespace MtxChess;
bool ok = true;
ok = testBehaviour() && ok;
ok = testLinked() && ok;
return ok?0:1;
}