मैं बूस्ट घुसपैठ स्मार्ट सूचक के साथ जाने का सुझाव देता हूं।
वहाँ भी स्कॉट मेयेर (यहाँ: http://www.aristeia.com/BookErrata/M29Source.html) से एक क्रियान्वयन है के रूप में 'More Effective C++'
में प्रकाशित
हालांकि, मामले में यह मदद करता है, मैं एक साधारण refcounting सूचक (
साथ बहुरूपी कार्य
और के लिए कुछ समर्थन yanked कस्टम deletors)। यह निर्णय अवांछित-जागरूक का निर्णय लिया गया है।
नोट: मैंने इसे गलत समझा। Polymorphic असाइनमेंट antoher परियोजना के लिए एक भिन्नता में थे। मेरे पास भी है लेकिन यह कस्टम डिलेक्टर का समर्थन नहीं करता है :) अगर कोई दिलचस्पी लेता है तो मुझे बताएं; (उदाहरण के लिए प्रसिद्ध 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;
}
क्या ओवरहेड वास्तव में खराब है? – Anycorn
सहमत हुए। ओवरहेड इतना छोटा है, कि यह बाधा नहीं होनी चाहिए। यदि आपके पास कहीं बाधाएं हैं, तो यह shared_ptr में नहीं है। – inestical
@inestical: इस मामले के लिए आप शायद सही हैं, लेकिन यह नहीं भूलें कि shared_ptr ढेर पर इसका पुनर्वित्त आवंटित करता है। ऐसा करने से दस लाख बार गंभीर ऊपरी हो सकता है। उदाहरण के लिए http://stackoverflow.com/questions/3628081/shared-ptr-horrible-speed – stijn