2011-07-21 60 views
0

我有一個GUI來與用戶交互,但是我有這樣的OOP設計問題。OOP設計問題(MFC C++實現)

通過對話框,用戶指定CDiscreteDistribution s,並將它們存儲在MyAppDoc類的std::vector<CDiscreteDistribution*>中用於序列化。通過另一個對話框,用戶爲特定的CParameter選擇一種類型CDistributionCDiscreteDistribution,CConstantDistributionCContinuousDistribution繼承CDistributionCParameter具有指向CDistribution成員變量的多態指針。 MyAppDoc有一個容器類CParameter。因此CDiscreteDistribution s被指出兩次,但只存在一次。

總之,MyAppDoc具有

  1. std::vector<CDiscreteDistribution*>
  2. CContainer其中有許多CParameter具有
    • CDistribution*其可以指向的
      • CDiscreteDistribution其是存儲在CDiscreteDistribution* S的一個一個以上
      • CConstantDistribution通過CParameter
      • CContinuousDistribution創建創建/銷燬/由CParameter

這種設計模式破壞是造成我不同噩夢在移植應用程序使用shared_ptr由於雙刪除和系列化(促進)。如果其中一個指向CDiscreteDistribution的指針是weak_ptr?如果是的話,應該在哪裏擁有指針?

感謝您的幫助!


編輯: 我重新思考推理具有std::vector<CDiscreteDistribution*>,它只是避免載體複製進入和退出的GUI。但是這些對象非常小,所以我打破了它們之間的聯繫,並且遭受了較小的性能影響。現在MyAppDoc有:

  1. std::vector<CDiscreteDistribution>
  2. CContainer其中有許多CParameter具有
    • CDistribution*它可以指向一個
      • CDiscreteDistribution創建/ CParameter破壞,從CDiscreteDistribution S的一個拷貝存儲在
      • 以上
      • CConstantDistribution創建/銷燬CParameter
      • CContinuousDistribution創建/ CParameter

毀滅,那麼我認爲問題的一部分是boost::serialization每個CDiscreteDistribution那些不知道對方的存在了兩個shared_ptr秒。現在唯一的問題是向後兼容以前版本創建的文件。

我認爲這個'解決方案'實際上只是避免了一個適當的設計!

+0

它可能會幫助你簡化或一般化您的具體情況一點。你可以把它變成更多的'Base' /'Derived'抽象例子來演示你的共享指針/等問題是什麼?我覺得很難用書面真正知道什麼之類的問題,對你正在運行了問題... – HostileFork

+0

感謝叉先生,你是對的,但我會離開它,因爲其他的反應已經使用了相同的命名法。 – Colin

回答

1

描述的問題是不夠了解的全部情況,併發症和確切的問題,但在一般 -

  • 我假設你想使用的shared_ptr不必須手動刪除()對象

  • 如果是這樣,看看你是否可以通過不使用shared_ptr來解決它,而是使用boost :: ptr_vector而不是原始指針向量;那麼ptr_vector會爲你處理內存管理。

我甚至不知道什麼是shared_ptr的會帶給你 - 這是很明顯的,我想從我有限的瞭解的情況說,該文件擁有CDiscreteDistribution對象。擁有其他兩種分配方式的人有責任將其刪除;這可以通過shared_ptr或其他方式來完成。 (你說的是'本地實例',但這並沒有多大意義 - 它們是在堆還是堆棧上實例化的?它們的壽命是什麼?它們的壽命爲什麼不同於DiscreteDistribution對象?什麼是'本地' - 什麼是本地的? )

+0

謝謝Roel,我沒有想過ptr_vector。由於對象是多態的,我想在CParameter中以相同的方式處理所有的分佈。我認爲我的想法如上所述,但正如我所說,這可能會避免更好的設計! – Colin

1

我同意羅爾的問題沒有完全說明。但是從原始指針到shared_ptr做了幾次廣泛的轉換,我可以給你一些建議。

  1. weak_ptr應該沒有必要,除非你有循環依賴。換句話說,如果一個對象A有一個shared_ptr對象B,並且對象B有一個shared_ptr回到對象A.在這種情況下,任何一個指針的引用計數都不可能變爲0,所以你需要手動干預以打破週期,或者使用weak_ptr來指定一側作爲從屬。
  2. 我很困惑,爲什麼你在使用shared_ptr時遇到雙刪除的問題。一般來說,智能指針的優點之一是您不必實際刪除它們。如果您已將全部轉換爲shared_ptr的原始指針,則不應該有此問題。如果您CConstantDistributionCContinuousDistribution對象實際上是當地人,而不是new(我不能告訴100%,如果這是從你描述的情況)分配的,你可以讓他們在你的構造函數初始化shared_ptr對象,如果你可以改變應用的代碼。這將允許你做出std::vector<CDiscreteDistribution*>shared_ptr一個容器CDiscreteDistribution代替。此時,除非您有如上所述的循環引用,否則根本不必擔心刪除這些對象。即使你這樣做,你也會將雙重刪除崩潰轉換爲內存泄漏,這通常不會太糟糕。
  3. 序列化可能很難。由於你用MFC標記了這個問題,我假設你使用的是MFC序列化。我一般在shared_ptr包裝的一切,當我序列化到一個文件沒有問題 - 我只是用.get()智能指針對象和序列化所產生的原始指針。當我序列化時,我讀取序列化文件中的原始指針,並將其包裝在shared_ptr糖果塗層中。這是序列化函數中的一些額外的代碼,但它可以工作。

如果我對某些情況猜測不準確,請隨時添加評論。如果可以,我很樂意提供幫助。

+0

感謝mwigdahl的幫助!我認爲雙刪除是由boost :: serialization創建兩個shared_ptr到同一個對象引起的。這是通過我上面的'解決方案'糾正的。 – Colin

+0

很酷,祝你好運!當然,如果你能做到的話,從一生的管理角度來看,傳遞一流的對象更容易! – mwigdahl

+0

你是什麼意思的第一類對象?在對象本身中,而不是指向對象的指針? – Colin