2013-03-26 54 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

相關問題