Reputation: 13575
I have a class, its object will be used by another class as following
class A
{
public:
void F() {...}
};
class B
{
public:
void G() { m_a->F(); ...} // use A's function
private:
A* m_a;
};
Thus it is wrong to call B::G() before the assignment of pointer m_a. Is this acceptable design? Or there is a better way to do it.
The question comes from developing a GUI application. I have a window under the main window to show some basic information of current operation, such as what is happening, how long does it take, and so on. I put this window as a singleton for easy access by the operations which may scatter anywhere, and find the code crashes when closing the GUI application. The crash is due to the window is deleted after the deletion of GUI application (such as qApp in Qt). I then just put a reference pointer of the window in the singleton. And when the window is constructed, I set the reference pointer. The deletion of the window is controlled by the main window. Thus the above mentioned crash problem is solved. But if other developer uses the singleton before the window is constructed, the code will crash too. Any good way to solve it? Or we can just accept it because it is developer's mistake to use it before constructing? Thanks a lot!
Upvotes: 1
Views: 78
Reputation: 126452
Invoking function G()
may result in Undefined Behavior if m_a
is not initialized, so you want to make sure that that's never the case. You have to change your code to make it look a bit like this:
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;
};
And by the way, in general you should use smart pointers (choose the type which realizes the appropriate ownership semantics) rather than raw pointers, unless you have a good reason to do that. This would even save you from manual initialization (assuming shared ownership here):
#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
};
Upvotes: 3
Reputation: 62389
Depending on your expected usage of the class, this can be an acceptable practice, but if you do that, you better change B::G()
to check the pointer first:
void G() { if (m_a) m_a->F(); ...}
And make sure to initialize m_a
in all constructors, at least to a null pointer if you don't currently have a real A
to point at.
Upvotes: 1
Reputation: 206546
You have to use the member initializer list to initialize m_a
rather than assign it.
It ensures you don't have to bother about getting m_a
assigned before calling other functions.
Upvotes: 2