持有对同一对象的const引用的对象。退出后会发生什么?

时间:2013-03-26 17:22:16

标签: c++ boost

我认为这是一个简单的问题,但我一直在盯着一些复杂的遗留代码,我再也看不到森林的树了。这个应用程序将运行数天,然后在退出时失败(当然它不适用于较短的工作!)我怀疑是一个SEGV。

我在下面用一些伪代码简化了这个案例(希望我做对了)。

在人类方面:我有一个类XYZ,它有很多东西,包括指向简单类ABC的指针向量(让我们假设它很简单)。这些指针在XYZ的析构函数中被删除;这就是所有析构函数。

然后我有一个简单的基类TheBase,它只有两个简单的虚方法,没有析构函数。

最后我有三个类,Tom和Dick(源自TheBase)和Harry(不是从TheBase派生的。)所有这三个类都是从对XYZ对象的const引用构造的。所以他们有一个对XYZ对象的const引用。他们也没有析构函数。

在主要内容中,为Tom,Dick和Harry对象中的每一个定义了boost :: shared_ptr。然后创建XYZ对象。接下来,XYZ对象作为const引用传递给Tom,Dick和Harry对象。在那之后,发生了大量的事情和主要的退出。

那么当所有这些事情超出范围时会发生什么?特别是XYZ对象?这会被正确处理吗?好像有些东西会被删除多次。

// A simple class (let's assume it is!)
class ABC
{
  // unimportant stuff.
}

// class XYZ has an array of ABC objects. All the destructor does is delete     those objects.
class XZY 
{
  public:
    XYZ(vector<string> v1,
        vector<string> v2,
        vector<string> v3 );
  virtual ~XYZ(){
          for ( i = 0; i < n, i++ ){
              delete my_abcs[i];
          }
  } 
private:
    vector <ABC*> my_abcs
  // lots of other methods & members
}

// Simple base class with only 2 simple virtual methods
class TheBase
{   
  public:
        virtual void minor_func1();
        virtual void minor_func2();
}

// A class derived from base class. Constructs with a const reference to an XYZ class.
class Tom:TheBase
{
    public:
        Tom( const XYZ & xyz )

    private:
        const XYZ & my_xyz; 
  // lots of other methods & members
}
Tom::Tom(const XYZ & xyz):my_xyz(xyz){
  ...
}

// Another class derived from base class. Constructs with a const reference to an XYZ class.
class Dick:TheBase
{
    public:
        Dick( const XYZ & xyz )

    private:
        const XYZ & my_xyz; 
    // lots of other methods & members
}
Dick::Dick(const XYZ & xyz):my_xyz(xyz){
...
}

// A class NOT derived from base class but still constructs with a const reference to an XYZ class.
class Harry:TheBase
{
  public:
        Harry( const XYZ & xyz )

    private:
        const XYZ & my_xyz; 
    // lots of other methods & members
}
Harry::Harry(const XYZ & xyz):my_xyz(xyz){
...
}

main (...){
  ...

  boost::shared_ptr <Tom> a_tom;
  boost::shared_ptr <Dick> a_dick;
  boost::shared_ptr <Harry> a_harry;
  ...

  XYZ a_xyz( ... );

  a_tom.reset( new Tom( a_xyz) );
  a_dick.reset( new Dick( a_xyz) );
  a_harry.reset( new harry( a_xyz) );

  ...
}

2 个答案:

答案 0 :(得分:3)

shared_ptr管理的对象将被破坏 指向它们的最后shared_ptr被破坏。本地 变量在超出范围时被破坏 它们被创建的逆序。在你的情况下,如果有 没有shared_ptr具有静态生命周期(或伪静态生命周期; 即在动态分配的对象中,它不是 破坏直到离开主要,如果有的话),然后a_xyz 将被破坏,然后由三个物体指向 shared_ptr如果这些对象不使用引用 他们的析构者a_xyzshared_ptr没有 复制到他们将比他们活得更长的地方,然后那里 应该没问题。

答案 1 :(得分:1)

  

我有一个类XYZ,它有很多东西,包括指向简单类ABC的指针向量(让我们假设它很简单)。这些指针在XYZ的析构函数中被删除;这就是所有析构函数。

顺便说一句,这个问题的答案是std::vector<std::unique_ptr<ABC>>,它封装了std::vector拥有类型中有问题的指针的事实,并且无需手动销毁它们。它还会阻止意外拷贝:如果你实现了一个非平凡的析构函数,你需要实现或阻止拷贝构造和拷贝分配(3的规则)。

使用std::vector<std::unique_ptr<ABC>>时,只能移动它,因此移动分配和移动构造将被取消阻止,而复制构造和复制分配将被阻止。

std::unique_ptr<T>有很少的开销。

当您需要访问基础.get()时,唯一的成本是对T*的大量调用,基本上没有运行时成本。

  

在主要内容中,为Tom,Dick和Harry对象中的每一个定义了boost :: shared_ptr。然后创建XYZ对象。接下来,XYZ对象作为const引用传递给Tom,Dick和Harry对象。在那之后,发生了大量的事情和主要的退出。

同一范围内的C ++中的对象将按照声明它们的相反顺序销毁。因此,汤姆,迪克和哈利的生命将比XYZ对象更长。

  

最后我有三个类,Tom和Dick(源自TheBase)和Harry(不是从TheBase派生的。)所有这三个类都是从对XYZ对象的const引用构造的。所以他们有一个对XYZ对象的const引用。他们也没有析构函数。

引用(在此上下文中)对引用事物的生命周期没有影响。引用不是智能指针,它们是不安全和未经检查的别名。通常,当您创建对某事物的引用时,确保该对象持续的时间长于对象的引用是您的工作。

如果XYZ超出范围,TomDickHarry中的任何一个访问其引用到XYZ,那么您已调用undefined行为。如果你不这样做,你就没有。

即使你没有,依靠这个也是一个坏习惯,因为你的代码会非常脆弱。

(要清楚:当我说“在这种情况下”时,我的意思是。有一个上下文,其中参考生命周期改变了有问题的对象的生命周期:何时直接构造引用 从一个临时(匿名)对象,该匿名对象的生命周期将扩展到引用的生命周期。但是,请注意,以这种方式间接构造的引用不具有此属性 - 所以{{1} }会延长匿名A& a = A();的生命周期,而A则不会,B& b = a;不起作用,但A& get_A() { return A(); }; A& a = get_A();会导致终身延期(不确定最后一个)。)