Jump to content
  • Advertisement
Sign in to follow this  
Black Knight

Constructor and non-heap objects

This topic is 3679 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,I have a class which has 4 members these are all derived from the same base Dialog class. Now the parent class constructor calls the other dialog boxes constructors like this :
LeftPanel::LeftPanel(HINSTANCE hInstance,HWND hParent,DWORD dlgID,DLGPROC Proc):
Dialog(hInstance,hParent,dlgID,Proc),
m_MapDialog(hInstance,m_hWnd,IDD_MAPDIALOG,MapDialog::DlgProc),
m_TerrainDialog(hInstance,m_hWnd,IDD_TERRAINDIALOG,TerrainDialog::DlgProc),
m_EntityDialog(hInstance,m_hWnd,IDD_ENTITYDIALOG,EntityDialog::DlgProc),
m_EventsDialog(hInstance,m_hWnd,IDD_EVENTSDIALOG,EventsDialog::DlgProc)
{
	

}


Is this a problem? The class is like this :
lass LeftPanel : public STWin::Dialog
{
public:
	friend class DAEditorViewport;

	LeftPanel(HINSTANCE hInstance,HWND hParent,DWORD dlgID,DLGPROC Proc);
	~LeftPanel();
    void            changeTabPage(int iTabID);
protected:
    //Pointer to the viewport 
	boost::weak_ptr<DAEditorViewport>   m_pViewport;
    //This is the tab control on the left panel
    STWin::TabControl m_TabControl;
	
    //The four dialogs which are members of the tab control
    MapDialog       m_MapDialog;
    TerrainDialog   m_TerrainDialog;
    EntityDialog    m_EntityDialog;
    EventsDialog    m_EventsDialog;

protected:
	BOOL			onInitDialog(LPARAM lParam);
	void			onCommand(WORD wNotifyCode,WORD wID,HWND hWndCtrl);
	BOOL	        onNotify(WPARAM wParam,LPARAM lParam,LRESULT *pResult);
	void			onHScroll(HWND hScrollBar,int iRequest,int iPosition);
	void			onSize(int iWidth,int iHeight,int iFlags);
	LRESULT			onNCActivate(HWND hParent,HWND hWnd,WPARAM wParam,LPARAM lParam);
};


Share this post


Link to post
Share on other sites
Advertisement
My guess is that m_hWnd is a protected member of the base, and the concern is perhaps whether or not the constructor that initialized it (that of the base) will be guaranteed to have completed successfully when execution reaches the point where that variable is passed to the member object constructors (m_MapDialog and the like)?

In which case, the answer is yes.

Share this post


Link to post
Share on other sites
Well I guess there is no problem as long as the initializer list first calls the base class constructor (so that m_hWnd is valid) and then the member constructors in the order they are declared in the class.
Would I need to store the members on the heap in the future?and allocate them in the initializer list?

boost::shared_ptr<EventsDialog> m_EventsDialog;
..
..

LeftPanel::LeftPanel(HINSTANCE hInstance,HWND hParent,DWORD dlgID,DLGPROC Proc):
Dialog(hInstance,hParent,dlgID,Proc),
m_MapDialog(hInstance,m_hWnd,IDD_MAPDIALOG,MapDialog::DlgProc),
m_TerrainDialog(hInstance,m_hWnd,IDD_TERRAINDIALOG,TerrainDialog::DlgProc),
m_EntityDialog(hInstance,m_hWnd,IDD_ENTITYDIALOG,EntityDialog::DlgProc),
m_EventsDialog(new EventsDialog(hInstance,m_hWnd,IDD_EVENTSDIALOG,EventsDialog::DlgProc))
{

}

Is it valid to set the shared_ptr like that in the constructor?Or do I need to use reset?

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
My guess is that m_hWnd is a protected member of the base, and the concern is perhaps whether or not the constructor that initialized it (that of the base) will be guaranteed to have completed successfully when execution reaches the point where that variable is passed to the member object constructors (m_MapDialog and the like)?

In which case, the answer is yes.


THe base Dialog class tries to create the dialog :

Dialog::Dialog(HINSTANCE hInstance,HWND hParent,DWORD dlgID,DLGPROC Proc):
WndObject(0,0,0,0)
{
m_hWnd = CreateDialogParam(hInstance,MAKEINTRESOURCE(dlgID),hParent,Proc,(LPARAM)this);
if(!m_hWnd){
MSGBOX_ERROR("Dialog Creation Failed!");
throw STE::RunTimeException("Can't create Dialog",FUNCTIONINFO);
}
RECT rRect;
GetWindowRect(m_hWnd,&rRect);
m_iPosX = rRect.left;
m_iPosY = rRect.top;
m_iWidth = rRect.right-rRect.left;
m_iHeight = rRect.bottom-rRect.top;

}


And throws an exception.I guess If an exception is throw the initializer list does not continue anymore and the constructor will return.

Share this post


Link to post
Share on other sites
Yes, if the constructor for a base class throws, no derived constructors will be executed (nor will any code generated from their initializer lists).

Keep in mind that the destructor for a constructor that throws will not be called.

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
Keep in mind that the destructor for a constructor that throws will not be called.

Yes I know this but I'm not 100% sure of how to free data if a constructor throws.

Here is an example :



myClass::myClass():
data(NULL),
data1(NULL),
data2(NULL)
{
//this succeeds
data=new int[100];

//this fails and throws
doSomethingThatThrows();

//these won't get executed
data1 = new Object();
data2 = new float[2];

}
myClass::~myClass()
{
delete []data;
delete data1;
delete []data2;
}



This example will leak because "data" will not get freed.

Should it be like this deleting NULL pointers are safe so:


myClass::myClass():
data(NULL),
data1(NULL),
data2(NULL)
{
try{
//this succeeds
data=new int[100];

//this fails and throws
doSomethingThatThrows();

//these won't get executed
data1 = new Object();
data2 = new float[2];
}
catch(...)
{
delete []data;
delete data1;
delete []data2;
}

}
myClass::~myClass()
{
delete []data;
delete data1;
delete []data2;
}



Share this post


Link to post
Share on other sites
delete doesn't set your pointers back to NULL. If you make that change in the catch block (delete data; data = NULL) then the destructor will not try and delete that same memory again.

Share this post


Link to post
Share on other sites
Quote:
Original post by Black Knight
Yes I know this but I'm not 100% sure of how to free data if a constructor throws.


As jpetrie said, if an exception is thrown in an object's constructor its destructor is never called.

Regardless of where an exception may be thrown from, we prevent potential memory leaks by using smart pointers:

std::auto_ptr<MyObject> ptr1 = new MyObject();
std::scoped_ptr<MyObject> ptr2 = new MyObject();
boost::scoped_array<MyObject> ptr3 = new MyObject[255];
etc.

If an exception initiates stack unwinding the smart pointer will be destroyed thereby releasing the resource for which it was responsible.

Share this post


Link to post
Share on other sites

LeftPanel::LeftPanel(HINSTANCE hInstance,HWND hParent,DWORD dlgID,DLGPROC Proc):
Dialog(hInstance,hParent,dlgID,Proc),
m_MapDialog(hInstance,m_hWnd,IDD_MAPDIALOG,MapDialog::DlgProc),
m_TerrainDialog(hInstance,m_hWnd,IDD_TERRAINDIALOG,TerrainDialog::DlgProc),
m_EntityDialog(hInstance,m_hWnd,IDD_ENTITYDIALOG,EntityDialog::DlgProc),
m_EventsDialog(hInstance,m_hWnd,IDD_EVENTSDIALOG,EventsDialog::DlgProc)
{
boost::shared_ptr<OtherObject) ptr2(new OtherObject());
}



In the example above, ptr2 will be freed when the constructor ends, am I right? As its a local object and the smart pointer will call delete on it when it goes out of scope.
So I need to store the smart pointers as members of the class.


LeftPanel::LeftPanel(HINSTANCE hInstance,HWND hParent,DWORD dlgID,DLGPROC Proc):
Dialog(hInstance,hParent,dlgID,Proc),
m_MapDialog(hInstance,m_hWnd,IDD_MAPDIALOG,MapDialog::DlgProc),
m_TerrainDialog(hInstance,m_hWnd,IDD_TERRAINDIALOG,TerrainDialog::DlgProc),
m_EntityDialog(hInstance,m_hWnd,IDD_ENTITYDIALOG,EntityDialog::DlgProc),
m_EventsDialog(hInstance,m_hWnd,IDD_EVENTSDIALOG,EventsDialog::DlgProc)
{
m_ptr2.reset(new OtherObject());
}




Will the smart pointer still call delete if an exception is thrown??I guess not because the destructor of LeftPanel will not be called and the smart pointer will not be destroyed at all.Am I right?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!