Skip to main content
GameDev.net gamedev.net
🔒 Locked

Deleting pointers in a vector.

Started by Programmer16 Oct 31, 2004 at 1:40 PM 2 replies 750+ views
Original Post
Programmer16
Programmer16
I'm working on making a toolbox for myself and my team to use, but I've run into a snag. I have a Window which has a std::vector variable inside it. The class works like this:

Window  g_MainWindow;
Window* g_ToolWindow = 0;
g_MainWindow.Create(...);
g_MainWindow.AddChild(...); // edit box
g_MainWindow.AddChild(...); // button
g_MainWindow.AddChild(...); // tool style window
g_ToolWindow = g_MainWindow.GetChild(2); // last child
g_ToolWindow->AddChild(...); // edit box
g_ToolWindow->AddChild(...); // button
g_ToolWindow->AddChild(...); // tool style window



Everything works fine until I add the second tool style window. Edit: Ok, everything doesn't work fine until then. I commented out the second tool style window, and when I run it, after closing the first tool window, I get the error below (whereas I wasn't getting the error until I closed all the windows before). If I run it I get this error:
First-chance exception in dfgwindows.exe (KERNEL32.DLL): 0xE06D7363: Microsoft C++ Exception
In Window::~Window() I loop through the list and delete each variable:

//########################################################################################
// Name:	~Window()
// Author:	Donny Beals on October 31st, 2004
// Scope:	Window
// Description:
// Cycles through each child window & deletes it, then calls this window's Destroy().
//########################################################################################
// Mod-log:
//########################################################################################
Window::~Window()
{
    std::vector<Window*>::iterator ChildItor = m_Children.begin();
    while(ChildItor != m_Children.end())
    {
        Window* TempWnd = (*ChildItor);
        delete TempWnd;
        ++ChildItor;
    }

    Destroy();
}

Edit 2: I also thought it might be a good idea to post the Destroy() function:

//########################################################################################
// Name:Destroy()
// Author:Donny Beals on October 31st, 2004
// Scope:Window
// Description:
// Unregisters the window, then destroys it, and sets all members to their defaults.
//########################################################################################
// Mod-log:
// October 31st, 2004 - DBeals added the code to reset all members to their defaults.
//########################################################################################
void Window::Destroy()
{
        UnregisterClass(m_ClassName.c_str(), GetModuleHandle(0));
        DestroyWindow(m_WindowHandle);
        m_WindowHandle    = 0;
        m_ParentHandle    = 0;
        m_ChildCount      = 0;
        m_ClassName       = "";
        m_Caption         = "";
        m_X               = 0;
        m_Y               = 0;
        m_Width           = 320;
        m_Height          = 240;
        m_UserData        = 0;
}

And my AddChild() function:

//########################################################################################
// Name:AddChild()
// Author:Donny Beals on October 31st, 2004
// Scope:Window
// Description:
// Creates a child window for the current window, and then adds it to its lists.
//########################################################################################
// Mod-log:
// Changed from CreateControl() to AddChild.
//########################################################################################
WNDCODE Window::AddChild(bool CreateWndClass, std::string ClassName, std::string Caption, unsigned int X, unsigned int Y, unsigned int Width, unsigned int Height, DWORD Style, DWORD StyleEx, int CtrlId, WNDPROC UserWindowProcedure, void* UserData)
{
    Window* ChildWindow         = new Window;
    ChildWindow->m_ParentHandle = m_WindowHandle;
    ChildWindow->m_ClassName    = ClassName;
    ChildWindow->m_Caption      = Caption;
    ChildWindow->m_X            = X;
    ChildWindow->m_Y            = Y;
    ChildWindow->m_Width        = Width;
    ChildWindow->m_Height       = Height;
    ChildWindow->m_UserData     = UserData;

    if(CreateWndClass)
    {
        WndClassEX WndClass;
        ZeroMemory(&WndClass, sizeof(WNDCLASSEX));
        WndClass.cbSize        = sizeof(WndClass);
        WndClass.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
        WndClass.hCursor       = LoadCursor(0, IDC_ARROW);
        WndClass.hIcon         = LoadIcon(0, IDI_APPLICATION);
        WndClass.hIconSm       = LoadIcon(0, IDI_APPLICATION);
        WndClass.hInstance     = GetModuleHandle(0);
        WndClass.lpfnWndProc   = UserWindowProcedure;
        WndClass.lpszClassName = ChildWindow->m_ClassName.c_str();
        WndClass.lpszMenuName  = 0;
        WndClass.style         = CS_VREDRAW | CS_HREDRAW | CS_CLASSDC;
        if(!RegisterClassEx(&WndClass))
        {
            std::string DebugString = "Error registering the window " + ClassName + ".\n";
            OutputDebugString(DebugString.c_str());
            return WCF_REGISTERCLASS;
        }
    }

    DWORD NewStyle = Style;
    if(!CreateWndClass)
    NewStyle |= WS_CHILD | WS_VISIBLE;
    
    ChildWindow->m_WindowHandle = CreateWindowEx(StyleEx, ChildWindow->m_ClassName.c_str(), ChildWindow->m_Caption.c_str(), NewStyle, ChildWindow->m_X, ChildWindow->m_Y, ChildWindow->m_Width, ChildWindow->m_Height, ChildWindow->m_ParentHandle, (HMENU)CtrlId, GetModuleHandle(0), ChildWindow->m_UserData);
    if(!ChildWindow->m_WindowHandle)
    {
        std::string DebugString = "Error creating a handle for the window \"" + ChildWindow->m_ClassName + "\".\n";
        OutputDebugString(DebugString.c_str());
        return WCF_CREATEWINDOW;
    }
    if(CreateWndClass)
        ShowWindow(ChildWindow->m_WindowHandle, SW_SHOWNORMAL);
    
    m_Children.push_back(ChildWindow);
    ++m_ChildCount;
    return WCS_OK;
}

I'm assuming their is something happening in my destructor that I don't fully understand (like the children's destructors not being called in the correct order or something). Any help would be appreciated! [Edited by - Programmer16 on October 31, 2004 3:17:55 PM]
Aprosenf
Aprosenf
I've had something similar happen with my window class. I'm guessing that something weird is happening with the way your window class interacts with Windows. Suppose you have a window heirarchy with a root A, A has a child B, and B has a child C. Here's what happens when you destroy window B:

  • The user closes window B
  • A WM_DESTROY message is sent to window C (child windows are destroyed before the parent window)
  • The message handler calls the Destroy() function on window C
  • Window C gets destroyed
  • A WM_DESTROY message is sent to window B
  • The message handler class the Destroy() function on window B
  • Window B tries to destroy window C again


Note that further problems can be exist, since your Destroy() function calls DestroyWindow(), which sends a WM_DESTROY message to that window. I suggest creating two functions, perhaps Destroy() and Destroying(), where one of them explicitly calls DestroyWindow() and the other is called after receiving a WM_DESTROY message to inform the Window class that it is being destroyed, rather than instructing it to destroy itself.
Programmer16
Programmer16
Wow, that's seems to be exactly what my problem was. I commented out my call to Destroy(), and it works fine.

Edit:
I also noticed a couple of errors with my code:
When I call destroy, I set m_ChildCount to 0, which messes with
deleting them later.
I (believe I) should be deleting the children in the Destroy()
function (put the loop in Destroy() and then call Destroy()
from the destructor). I did this and it seems to work fine.
Also, I put a call to DestroyWindow() before the loop.

Thanks Aprosenf!

[Edited by - Programmer16 on October 31, 2004 9:30:43 PM]
hplus0603
hplus0603
The trick is to make sure that the child windows that get destroyed remove themselves from the list of child windows in the parent window, if you keep a list parallel to Windows. The other trick is to not duplicate the list that Windows already has. If someone wants the YourWindow * for a window, call GetWindowLong(GWL_USERDATA) to get it back from the HWND that you can easily get from Windows.
enum Bool { True, False, FileNotFound };

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.