0

Ok, then. I started learning C++, and my task is to create a process manager with the Win32 API. It is going to look like this:

image

I have a TBuffer class: (Buffer will keep information about the processes)

#pragma once

#include <wtypes.h>

#define BUFFER_SIZE 10
#define WM_UPDATELIST WM_USER

enum TProcessState { psEmpty, psNew, psRunning, psTerminated, psError };

struct TProcessInfo 
{
    TProcessState State;
    char Name[100];
    HANDLE Handle;
    int PID;
    int UserTime, KenelTime;
};

class TBuffer
{
private:
    HWND Wnd;
    CRITICAL_SECTION cs;
    TProcessInfo Buf[BUFFER_SIZE];
public:
    TBuffer(HWND AWnd);
    ~TBuffer();
    int Count();
    int AddProcess(char *AName);
    void Get(int Id, TProcessInfo &Pi);
    void Set(int Id, const TProcessInfo Pi);
    const char* ProcessStateToString(TProcessState state);
};

The class constructor has the following realization:

TBuffer::TBuffer(HWND AWnd)
{
    Wnd = AWnd;
    InitializeCriticalSection(&cs);
    for (int i = 0; i < BUFFER_SIZE; i++)
    {
        Buf[i].State = psEmpty;
        Buf[i].Handle = 0;
        Buf[i].Name[0] = 0;
        Buf[i].PID = 0;
        Buf[i].UserTime = 0;
        Buf[i].Handle = 0;
    }
}

And the destructor:

TBuffer::~TBuffer()
{
    DeleteCriticalSection(&cs);
}

The method using critical section:

void TBuffer::Set(int Id, const TProcessInfo Pi)
{
    EnterCriticalSection(&cs);
    ...
    LeaveCriticalSection(&cs);
}

In the main .cpp file, I have a global variable:

TBuffer *Buffer;

And in the MainWndProc function where messages are processed, in the case WM_INITDIALOG I am asked to create a TBuffer class object to initialize the critical section and so on:

case WM_INITDIALOG:
{
    TBuffer Buf(hWnd);
    Buffer = &Buf;
    ...
    return TRUE;
}

My problem is that, as I read, the class object after return TRUE is going out of scope and its destructor is called. That's why the critical section is deleted and then other class methods like Set() and Get() are not able to enter the critical section. So I'm looking for a way to leave the object in scope. I think that something is wrong in WM_INITDIALOG with object creation.

By the way, when the WM_DESTROY message is processed, I free the allocated memory for the global variable:

case WM_DESTROY:
    delete[] Buffer;
    PostQuitMessage(0);
    return TRUE;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Ilya
  • 5
  • 3
  • 1
    Do not tag both C and C++ except for questions about differences or interactions between the two languages. – Eric Postpischil Oct 24 '21 at 13:53
  • 1
    you allocate temporary object in stack ( `TBuffer Buf(hWnd)` ) which of course not valid after exit from scope. and can not be used after this. even more - you try `delete[]` it despite you not allocate object with `new`. – RbMm Oct 24 '21 at 13:56
  • 1
    The way to allocate a new object in C is to use the `new` operator: `Buffer = new TBuffer(hWnd);`. – Eric Postpischil Oct 24 '21 at 13:57
  • FYI: code like this: `EnterCriticalSection(&cs); ... LeaveCriticalSection(&cs);` is no good if `...` throws an exception. You would basically have a deadlock thread if it is waiting for the critical section to be released. Instead of this, use RAII such as `std::lock_guard` or if not that, write a class that automatically calls `LeaveCrititcalSection` on destruction, create an object of that type, and assign `cs` to it. This is the big advantage that C++ has over C in this regard -- writing this type of code safely becomes much easier. – PaulMcKenzie Oct 24 '21 at 14:25

1 Answers1

1

You're correct in your understanding,

case WM_INITDIALOG:
{
    TBuffer Buf(hWnd);
    Buffer = &Buf;
    ...
    return TRUE; // <-- Buf is destructed here, Buffer is now a dangling pointer
}

To allocate something that lives longer than its enclosing scope, allocate it on the heap using new:

case WM_INITDIALOG:
{
    Buffer = new TBuffer(hWnd);
    ...
    return TRUE;
}

And remember to delete later.

qz-
  • 674
  • 1
  • 4
  • 14
  • Remember to delete with scalar `delete`, not array `delete[]`, see https://stackoverflow.com/questions/2425728/delete-vs-delete-operators-in-c – Alex Guteniev Oct 24 '21 at 15:22