2013-01-31 68 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指向的位置。