The object itself (this) is it a leak if its constructor throws?

Mar 16, 2024 at 7:37pm
if the ctor throws, then the object this has already received the memory (some new or alloc has been executed)... so, does the object this leak?

the only possible way that it didn't leak is if free is called upon ctor throw!!


this happens even if this is an empty class -- no non-static data members!

Correct??
I know the destructor is not called when constructor throws...
Last edited on Mar 16, 2024 at 10:19pm
Mar 16, 2024 at 10:20pm
If the constructor throws the memory will be freed so there is no memory leak. Already constructed data members will have their destructors called.
Mar 16, 2024 at 10:22pm
There's no memory leak. The memory for the object is returned by new.

If you inspect the generated code for this program:
1
2
3
bool g(); 
struct a { a() { if (g()) throw 0; } }; 
a* f() { return new a; }

You can see that it conditionally calls operator delete.
https://godbolt.org/z/4sjKWE8f4

For example:
f():
        push    rbp
        push    rbx
        sub     rsp, 8
        mov     edi, 1
        call    operator new(unsigned long)
        mov     rbx, rax
        call    g()
        test    al, al
        jne     .L6
        mov     rax, rbx
        add     rsp, 8
        pop     rbx
        pop     rbp
        ret
.L6:
        mov     edi, 4
        call    __cxa_allocate_exception
        mov     rdi, rax
        mov     DWORD PTR [rax], 0
        mov     edx, 0
        mov     esi, OFFSET FLAT:_ZTIi
        call    __cxa_throw
        mov     rbp, rax
        mov     esi, 1
        mov     rdi, rbx
        call    operator delete(void*, unsigned long)
        mov     rdi, rbp
        call    _Unwind_Resume
Mar 16, 2024 at 10:30pm
But the destructor is not called when constructor throws...correct??
Last edited on Mar 16, 2024 at 10:47pm
Mar 16, 2024 at 11:56pm
Right. The destructor isn't called, because the object's lifetime doesn't start until its constructor is complete.

That being said, member and base class subobjects get destroyed provided they are already within their lifetime when the exception is thrown.
Mar 17, 2024 at 3:36am
You have to be careful with constructors. Most of the time they Do The Right Thing™.

The problem is if you start managing your own resources.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct leaks_memory
{
  char * s;

  leaks_memory()
  : s{nullptr}
  {
    s = new char[40];
    throw "something";
  }

  ~leaks_memory()
  {
    if (s) delete [] s;
  }
};

That’s pretty academic-looking, but it easily happens when managing some complex resources.

Here’s another leaky class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct leaks_resources
{
  FILE * f;

  leaks_resources()
  : f{nullptr}
  {
    f = fopen( "a-valid-file.txt", "r" );
    throw "something";
  }

  ~leaks_resources()
  {
    if (f) fclose( f );
  }
};

There are all kinds of ways you can write a constructor to fail.

Fortunately, modern C++ provides a lot of abstractions to help with that. Here is the first example again, except it does not leak memory:

1
2
3
4
5
6
7
8
9
10
struct doesnt_leak_memory
{
  std::unique_ptr <char[]> s;

  doesnt_leak_memory()
  {
    s.reset( new char[40] );
    throw "something";
  }
};

Hope this helps.
Mar 17, 2024 at 4:56am
The pitfalls in leaks_resources and leaks_memory exist and are are common outside of constructors too.
Mar 17, 2024 at 7:43pm
Excellent comments! Thank you again!!
Topic archived. No new replies allowed.