简单的引用计数:智能指针

发布于 2024-09-17 19:46:44 字数 5187 浏览 6 评论 0原文

我想使用智能指针实现简单的引用计数。变量pointer表示指向存储对象的指针,reference_count表示该对象的副本总数。

  • 如果我们使用 NULL 初始化一个对象:reference_count = -1 else reference_count = 1
  • 复制构造函数和操作符 = 递增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;
}

这种解决方案的优点或缺点在哪里?大量数据的运行速度、转换、继承可能出现的问题等怎么样?感谢您的帮助。

对于这个例子,我还有一个问题:哪种类型的智能指针(共享、作用域)最适合这样的数据结构:

//Class with cross-references to points p1, p2
class PointTopo
{
private:
    double x, y;
    PointTopo * p1;
    Point * p2;

public:
    PointTopo(double xx, double yy): x(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;
...
};

感谢您的帮助...

I would like to implement a simple reference counting using smart pointers. The variable pointer represents pointer to stored object, reference_count represents total count of copies of the object.

  • if we initialize an object using NULL: reference_count = -1 else reference_count = 1
  • copy ctor and operator = increment reference_count
  • destructor decrement reference_count and if there is no other reference to pointed object performs its deletion.

Here is my code:

#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;
        }
};    

Here is my testing code, class sample stores 2D point and two pointers to any other 2D points.

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';
    }

};

List of 2D points:

#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();

        }

    }
};

Test code:

#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;
}

Where are advanteges or disadvanteges of such solution? What about running speed for huge amount of data, casting, possible problems with inheritance, etc. Thanx for your help.

I had one more question to this example: Which type of the smart pointer (shared, scoped) would be for such a data structures the most suitable:

//Class with cross-references to points p1, p2
class PointTopo
{
private:
    double x, y;
    PointTopo * p1;
    Point * p2;

public:
    PointTopo(double xx, double yy): x(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;
...
};

Thanks for your help...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

四叶草在未来唯美盛开 2024-09-24 19:46:45

您的引用计数不起作用。

如果将两个智能指针复制或分配在一起,它们需要使用相同的位置来执行计数。

目前,每个对象都有自己的计数,因此它们可能会不同步。

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;
            }
        }
};

Your reference counting does not work.

If you copy or assign two smart pointers together they need to use the same location to perform the counting.

Currently each object keeps its own count and thus they may become out of sync.

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
}

Edit:

Illustrate problem as requested in comments.

At the point. Where we have just created z. But not yet done 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;
    }

If anybody tries to use 'y' now we have undefined behavior as it contains a pointer to memory that has been de-allocated.

Edit Classic (but overly simplistic smart pointer:

#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;
            }
        }
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文