【问题标题】:Smart pointers, or "better" destructor智能指针,或“更好”的析构函数
【发布时间】:2011-04-06 21:51:33
【问题描述】:

哪种类型的智能指针(共享的,作用域的)最适合这种数据结构......

结构1:

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

public:
    PointTopo(double xx, double yy): x(xx), y(yy) {this-> p1 = NULL; this->p2 = NULL;}
    ...

};

结构2:

//Class  with cross references: topological model for Delaunay triangulation
class Edge
{
   private:
      Point * start; //Only 2D point without topo information
      Edge *next;
      Edge *previous;
      Edge *twin;
...
};

我想使用向量存储 Edges 和 PointTopo:

class PointsTopoList
{
   private:
      std::vector <PointTopo *> points;
   public:

      inline void push_back ( PointTopo *p ) { points.push_back ( p );}
      ~PointsTopoList() {clear();}
      void clear()
        {
           for ( TNodes2DList::iterator i_points= points.begin(); i_points!= points.end(); ++i_points)
            {
            if ( *i_points!= NULL )
            {
                delete *i_points;
                *i_points= NULL;
            }

             points.clear();
        }

}

但是析构函数有问题,所以想知道要不要使用引用计数。

int main()
{
   PointTopo *p1 = new PointTopo(0,0);
   PointTopo *p2 = new PointTopo(10,10);
   PointTopo *p3 = new PointTopo(20,20);
   PointTopo *p4 = new PointTopo(30,30);

   PointsTopoList tl1;
   tl1.push_back(p1);
   tl1.push_back(p2);
   tl1.push_back(p3);
   tl1.push_back(p4);

   PointsTopoList tl2;
   tl2.push_back(p1);  //P1 is stored in tl1 and tl2
   tl2.push_back(p2);  //P2 is stored in tl1 and tl2
}

点 p1、p2 将存储在两个列表 tl1、tl2 中。 tl2 的析构函数导致异常,点 p1 和 p2 已使用 tl1 析构函数删除。

这个例子不是合成的。想象一下,nl2 代表 nl1 的子集,例如 nl1 的凸包......

我认为,如果没有引用计数就无法解决这个问题......所以我尝试使用一些智能指针......

非常感谢您的帮助...

【问题讨论】:

    标签: c++ destructor reference-counting datamodel smart-pointers


    【解决方案1】:

    shared_ptr&lt;&gt; 对指向同一个对象的多个指针进行引用计数和管理,当指向它的最后一个指针被销毁时删除该对象。

    scoped_ptr&lt;&gt; 使指针的行为类似于堆栈变量,一旦指针超出范围,它就会删除指向的对象。这不是您在此处寻找的行为。

    在您的用例中,shared_ptr&lt;&gt; 提供的引用计数是您想要的。

    【讨论】:

    • 使用指针非常快......使用shared_ptr是否会显着降低程序的速度?
    • @Ian:不,很可能不会。基本上创建指针变量、复制它们并销毁它们比它们在智能指针上的等价物要快。但除非那是您的程序所做的主要事情,否则您不太可能看到差异。 取消引用(也就是实际使用指向的数据)应该同样快。
    • @Ian,唯一的开销应该是分配和销毁指针。访问应该通过内联函数,一个好的编译器会优化掉该代码,使其与原始指针相同。
    • @Ian - 如果您确实发现速度是一个问题,那么您可以尝试侵入式版本。它们要求您修改要指向的对象,但不会创建额外的引用计数对象等。我怀疑你甚至会注意到,但如果你这样做了,那是一种选择。
    • ReferenceCounting 当然会增加性能开销。但实际上只有非常特殊的情况才会受到影响,因为开销很低。然而 shared_ptr 确实显着提高了 C++ 代码的健壮性和可读性。这反过来又有助于“开发人员性能”,在大多数情况下,这比使用引用计数对理论上的性能影响更重要。
    【解决方案2】:

    tl2 的析构函数导致异常,点 p1 和 p2 已使用 tl1 析构函数删除。

    您尝试delete 对象p1(和p2)两次。这会调用 UB——这是一件坏事。试试shared_ptr(引用计数的智能指针),它在std::tr1 命名空间(有关更多详细信息,请参阅您的编译器文档)或Boost 中都可用。

    要做的另一件事是复制对象(而不是像现在这样复制指针)。这需要复制 PointTopo 对象。

    (就我个人而言,我倾向于将unique_ptr 单独用于EdgePointTopo 的成员。)

    【讨论】:

      【解决方案3】:

      您需要的是 boost::shared_ptr

      【讨论】:

        猜你喜欢
        • 2012-04-17
        • 2018-02-02
        • 2016-03-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-20
        • 1970-01-01
        相关资源
        最近更新 更多