2013-03-26 64 views
1

我认为这是一个简单的问题,但我一直在盯着一些复杂的遗留代码,我不能再看到森林的树木。这些应用程序将运行几天,然后退出时失败(当然,它不会让更短的工作!)我怀疑SEGV。持有对同一对象的const引用的对象。退出时会发生什么?

我简化了下面的一些伪代码的情况(希望我已经明白了)。

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

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

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

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

那么当所有这些东西超出范围时会发生什么?特别是XYZ对象?这会被正确处理吗?似乎某些内容会被删除多次。当 最后shared_ptr指向它们被破坏由shared_ptr管理

// 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)); 

    ... 
} 
+0

@Po你的意思是'vector ',而不是'vector '。如果'ABC'是一个带有值语义的简单对象,它支持复制,这当然是更好的解决方案。 – 2013-03-26 17:35:19

+0

另外,'TheBase'的析构函数可能应该是虚拟的。 (在代码中给出,它不是必要的,但在一般情况下,如果基类有虚函数,它似乎是合理的指望有人试图通过指针删除派生类对象的基础。) – 2013-03-26 17:36:44

+0

@JamesKanze啊,谢谢 - 我没有阅读那里的指针。尽管如此,我还是认为向量被设计为处理指针......此外,为了以防万一,最好使用虚拟析构函数。 – Polar 2013-03-26 17:36:58

回答

1

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

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

std::vector<std::unique_ptr<ABC>>,它只能被移动,所以移动分配和移动结构被解除阻止,而复制构造和复制分配被阻止。

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

当您需要访问底层T*时,唯一的代价是对.get()的一堆调用,它基本上具有零运行时成本。

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

在同一范围内的C++中的对象按声明相反的顺序销毁。所以汤姆,迪克和哈利的一生会比XYZ的对象更长。

最后,我有三个类,汤和Dick(来自TheBase衍生)和哈里(而不是从TheBase的。)所有他们三个从一常量引用的XYZ对象构造的;所以他们有一个对XYZ对象的const引用。他们也没有析构函数。

参考文献(在此上下文中)对所引用事物的寿命没有影响。引用不是智能指针,它们是不安全和未经检查的别名。一般来说,当你创建一个对某个东西的引用时,你的工作就是确保该对象的持续时间比该对象的引用长。

如果XYZ后超出范围的任何TomDickHarry访问他们的参考TO- XYZ,那么你已经调用未定义的行为。如果你不这样做。

即使你还没有,它可以是一个坏习惯,就靠这个,因为你的代码将是极其脆弱的。

(要明确:当我说“在此上下文中”,我的意思是它有一个在其中一个参考寿命改变所讨论的对象的生命周期的上下文:当基准被构造直接从临时(匿名)对象,则该匿名对象的生命周期将扩展到引用的生命周期。但是,请注意,以这种方式间接构造的引用不具有此属性 - 因此A& a = A();将延长匿名A,而B& b = a;将不会和A& get_A() { return A(); }; A& a = get_A();不起作用,但A get_A() { return A(); }; A& a = get_A();确实导致寿命延长(不确定最后一次)。)

+0

谢谢大家。我意识到,我可能会把这个问题与我在XYZ中指向矢量的问题混淆起来;我主要想强调XYZ不简单(至少可以说!),并用记忆做一些奇怪的事情。 (仍然unique_ptr上的信息很方便。)我真的对XYZ对象发生了什么感兴趣。我很确定所做的是不是很好的做法,但并不完全确定它的含义。我想这不是我的主要问题,但仍需要清理。 – user1074069 2013-03-26 18:32:42

3

的对象将被破坏。本地 变量在超出范围时被破坏,其创建的逆向顺序为 。在你的情况,如果有 没有shared_ptr静态寿命(或伪静态的一生; 即在一个动态分配的对象,这将不会是 破坏,直到离开主,如果有的话)之后,再a_xyz 会遭到破坏,则 shared_ptr指出的三个对象。 如果这些对象不使用参考 a_xyz在析构函数(和shared_ptr没有 拷贝到某个地方,他们会活得比主),那么 应该没有问题。

+0

简洁的答案!谢谢。 – user1074069 2013-03-26 18:34:13

相关问题