我想使用智能指针实现一个简单的引用计数.变量指针表示存储对象的指针,reference_count表示对象的副本总数.
>如果我们使用NULL初始化对象:reference_count = -1 else reference_count = 1
> copy ctor和operator = increment reference_count
>析构函数递减reference_count并且如果没有对指向对象的其他引用则执行其删除.
这是我的代码:
#ifndef smart_pointer_H #define smart_pointer_H template < typename T > class smart_pointer { private: T* pointer; int reference_count; public: smart_pointer() : pointer(0),reference_count(-1) {} smart_pointer(T* p) : pointer(p) { if (p != NULL) { this->reference_count = 1; } else { this->reference_count = -1; } } smart_pointer(const smart_pointer <T> & p) : pointer(p.pointer),reference_count(p.reference_count + 1) {} bool operator == (const smart_pointer <T>& p) { return pointer == p.pointer; } bool operator != (const smart_pointer <T>& p) { return pointer != p.pointer; } ~ smart_pointer() { if(-- reference_count == 0) { std::cout << "Destructing: " << '\n'; delete pointer; } } T& operator * () { return *pointer; } T* operator -> () { return pointer; } smart_pointer <T> & operator = (const smart_pointer <T> & p) { if (this != &p) { if( -- reference_count == 0) { delete pointer; } pointer = p.pointer; reference_count = p.reference_count + 1; } return *this; } };
这是我的测试代码,类样本存储2D点和两个指向任何其他2D点的指针.
template < typename T > class smart_pointer; class Point { private: double x,y; smart_pointer <Point> p1; smart_pointer <Point> p2; public: Point(double xx,double yy): x(xx),y(yy) {this-> p1 = NULL; this->p2 = NULL;} Point(double xx,double yy,smart_pointer <Point> p1,smart_pointer <Point> p2): x(xx),y(yy) {this-> p1 = p1,this->p2 = p2; } double getX(){ return x;} double getY(){ return y;} void setX(double xx) {this->x = xx;} void setY(double yy) {this->y = yy;} void setP1(smart_pointer <Point> p1) {this->p1 = p1;} void setP2(smart_pointer <Point> p2) {this->p2 = p2;} void print() { std::cout << "x= " << x << " y= " << y << '\n'; std::cout << "p1" << '\n'; if (p1 != NULL) { p1->print(); } std::cout << "p2" << '\n'; if (p2 != NULL) { p2->print(); } std::cout << '\n'; } };
2D点列表:
#include "Point.h" class PointsList { private: std::vector <smart_pointer <Point> > points; public: smart_pointer <Point> & operator [] ( int index ) {return points[index];} public: void push_back(smart_pointer <Point> p) {points.push_back(p);} void erase(unsigned int index) {points.erase(points.begin() += index );} void printPoints() { std::cout << "List of points" << '\n'; for (unsigned int i = 0; i < points.size(); i++) { points[i]->print(); } } };
测试代码:
#include "Point.h" #include "PointsList.h" int main() { smart_pointer <Point> pb = NULL; pb = (new Point(0,0)); smart_pointer <Point> p0(new Point(0,0)); p0->print(); smart_pointer <Point> p1(new Point(10,10)); p1->print(); smart_pointer <Point> p2(new Point(20,20)); p2->print(); smart_pointer <Point> p3(new Point(30,30)); p3->print(); smart_pointer <Point> pa(p3); p0->setP1(p2); p0->setP2(p3); p0->print(); p0 = p1; p0->print(); p0->print(); PointsList pl1; pl1.push_back(p0); pl1.push_back(p1); PointsList pl2; pl2.push_back(p2); pl2.push_back(p3); pl1.erase(0); pl1.printPoints(); pl2.printPoints(); return 0; }
这种解决方案的优势或不足之处在哪里?如何为大量数据运行速度,转换,可能的继承问题等等.Thanx为您提供帮助.
我对这个例子还有一个问题:哪种类型的智能指针(共享,作用域)最适合这样的数据结构:
//Class with cross-references to points p1,p2 class PointTopo { private: double x,y; PointTopo * p1; Point * p2; public: PointTopo(double xx,y(yy) {this-> p1 = NULL; this->p2 = NULL;} ...
};
//Class with cross references: topological model for Delaunay triangulation class Edge { private: Point2D * start; Edge *next; Edge *prevIoUs; Edge *twin; ... };
谢谢你的帮助…
解决方法
您的引用计数不起作用.
如果您将两个智能指针复制或分配在一起,则需要使用相同的位置来执行计数.
目前,每个对象都保留自己的计数,因此它们可能会变得不同步.
smart_pointer<int> x(new x); // x.pointer: <good> x.reference_count: 1 { smart_pointer<int> y; // y.pointer: NULL y.reference_count: -1 y = x; // x.pointer: <good> x.reference_count: 1 // y.pointer: <good> y.reference_count: 2 smart_pointer<int> z; x = z; // x.pointer: NULL x.reference_count: 0 (BAD) // z.pointer: NULL z.reference_count: -1 // y.pointer: <bad> (it was deleted by x) y.reference_count: 2 }
编辑:
按照评论中的要求说明问题.
在这一点上.我们刚刚创建了z.但尚未完成x = z;
x { pointer: 0xabcd1234 reference_count: 1 } y { pointer: 0xabcd1234 reference_count: 2 } z { pointer: NULL reference_count: -1 } // So here is your assignment operator. // Doing the `x = z` we will walk through the following code. // smart_pointer <T> & operator = (const smart_pointer <T> & p) { if (this != &p) { // We get here. // Left hand side is 'x' so this condition will be true. if( -- reference_count == 0) { // Now we are deleting a pointer. // That is held by 'x' delete pointer; // But 'y' is holding a pointer with the same value. // Now y is holding a pointer to a deleted variable. } // Here we copy 'z' into 'x' // Copy the pointer. That happens to be NULL. pointer = p.pointer; // Now we copy and increment the reference count. // So 'x' has a value of 0 while 'z' has a value of -1. // This also breaks the invariant on 'x' that NULL values should // have a reference count of -1 (as X is NULL and ref-count is 0) reference_count = p.reference_count + 1; } return *this; }
如果有人试图使用’y’,我们现在有未定义的行为,因为它包含一个指向已经解除分配的内存的指针.
编辑经典(但过于简单的智能指针:
#include <vector> template<typename T> class SP { T* object; size_t* count; public: SP(T* data) try // Use weird try around initializer list to catch new throwing. // If it does we delete data to stop it from leaking. :object(data),count(data ? new int(1) : NULL) { /* This is the constructor */} catch(...) {delete data;} SP(): object(NULL),count(NULL) {} //SP(T* data): object(data),count(new int(1)) {} // Lined up here so it look neat but implemented above to use weird try catch SP(SP<T> const& rhs): object(rhs.object),count(rhs.count) {if (count) {++(*count);}} SP<T>& operator=(SP<T> rhs) // Note implicit copy construction in rhs { // Using copy swap idiom for assignment. // The copy is hidden because the parameter is pass by value. this->swap(rhs); return *this; } void swap(SP<T>& rhs) throw() { std::swap(object,rhs.object); std::swap(count,rhs.count); } ~SP() { if ((count) && (--(*count) == 0)) { delete count; delete object; } } };