2013-01-31 70 views
1

我有一個類之前使用它,它的目的將通過另一個類可以用作以下崩潰,施工

class A 
{ 
public: 
    void F() {...} 
}; 

class B 
{ 
public: 
    void G() { m_a->F(); ...} // use A's function 

private: 
    A* m_a; 
}; 

因此這是錯誤的調用B :: G()指針M_A的分配之前。這是可接受的設計?或者有更好的方法來做到這一點。

問題來自開發一個GUI應用程序。我在主窗口下面有一個窗口,顯示當前操作的一些基本信息,例如發生了什麼,需要多長時間等等。我把這個窗口作爲一個單獨的元素,以便可以隨處散佈的操作輕鬆訪問,並在關閉GUI應用程序時發現代碼崩潰。崩潰是由於窗口在刪除GUI應用程序(如qt中的qApp)後被刪除。然後,我只是把一個窗口的引用指針放在單例中。當窗口被構建時,我設置了引用指針。窗口的刪除由主窗口控制。從而解決了上述崩潰問題。但是如果其他開發人員在構建窗口之前使用單例,代碼也會崩潰。有什麼好辦法解決它?或者我們可以接受它,因爲在構建之前使用它是開發人員的錯誤?非常感謝!

+0

這取決於您在文檔中編寫的內容! –

+0

它怎麼可能是一個可接受的設計?調用'G()'是未定義的行爲。也許我沒有得到它 –

回答

2

您必須使用member initializer list初始化m_a而不是分配它。 它確保您在調用其他函數之前不必擔心分配m_a

+0

我不認爲'G'應該是OP代碼中的構造函數... –

+1

@OliCharlesworth:是的,但是如果OP對演員的函數調用序列感到困擾,只有兩種方法:1.將其記錄在接口文檔中或2.在構建過程中初始化指針成員。 –

3

如果m_a未初始化,調用函數G()可能會導致未定義的行爲,因此您要確保永遠不會發生這種情況。你必須改變你的代碼,使它看起來有點像這樣:

class B 
{ 

public: 

    B() : m_a(nullptr) { } // m_a always initialized! 

    bool G() 
    { 
     if (m_a == nullptr) return false; // No Undefined Behavior! 
     m_a->F(); // This call is safe now 
     ... 
     return true; 
    } 

private: 

    A* m_a; 

}; 

順便說一下,一般你應該使用智能指針(選擇哪個實現相應的所有權語義的類型),而不是原始指針,除非你有充分的理由這樣做。這甚至會節省你從手動初始化(這裏假設共享所有權):

#include <memory> 

class B 
{ 

public: 

    bool G() 
    { 
     if (m_a == nullptr) return false; // No Undefined Behavior! 
     m_a->F(); // This call is safe now 
     ... 
     return true; 
    } 

private: 

    std::shared_ptr<A> m_a; // Automatically initalized to nullptr 

}; 
+2

問題陳述中沒有足夠的信息來證明「你應該**使用智能指針......」。也許「你**應該考慮**使用智能指針......」。 –

+1

@PeteBecker:我知道你的意思,但即使僅僅是智能指針初始化爲nullptr,而原始指針不需要手動初始化這一事實在這個例子中也有直接的好處。而且,在Modern C++中,必須有一個很好的理由**不要使用智能指針來選擇原始指針。雖然確實存在這些情況,但我相信它們並不代表違約情況。如果這個例子沒有提到選擇原始指針的好理由,我覺得有必要提到應該使用智能指針。因此我的措辭。 –

+0

更改所有權語義以便不必初始化某些東西就是內置式設計。 –

1

根據類的預期用途,這可能是一個可以接受的做法,但如果你這樣做,你最好改變B::G()檢查指針第一:

void G() { if (m_a) m_a->F(); ...} 

並確保在所有構造函數初始化m_a,至少要一個空指針,如果你現在還沒有一個真正的A指向的位置。