1

I have a class that allocates memory and can throw an exception in constructor, e.g.:

class A
{
    int *x;
public:
    A () { x = new int; throw 0;}
    ~A () { delete x; }
};

I want to create objects of such class dynamically. How should I do it to prevent memory leaks? I've tried to do create objects in a try block and delete in a catch block, but address-sanitizer have reported SEGV on unknown address.

int main()
{
    A *a;
    try { a = new A; }
    catch(int) { delete a; } // AddressSanitizer: SEGV on unknown address
}

Without deletion of the object we have (obviously) a memory leak and leak-sanitizer reports that.

int main()
{
    A *a;
    try { a = new A; }
    catch(int) {} // LeakSanitizer: detected memory leaks
}

However without try - catch both sanitizers are silent. I am wondering is there still a memory leak and, and if so, how to fix it?

int main()
{
    A *a;
    a = new A; // terminate called after throwing an instance of 'int'
}

UPD: Yes, I know about shared pointers. My question is mostly about the last case (without handling an exception). Why are sanitizers silent? Is it just leak-sanitizer flow or is there really no leak?

hant0508
  • 528
  • 1
  • 9
  • 19
  • Possible duplicate of [What's the best practice to prevent memory leak if an exception thrown in constructor?](https://stackoverflow.com/questions/18324126/whats-the-best-practice-to-prevent-memory-leak-if-an-exception-thrown-in-constr) – perivesta Mar 28 '19 at 13:33
  • in addition to the previous comment this might give some clearance [What happens if a constructor throws an exception?](https://stackoverflow.com/questions/32323406/what-happens-if-a-constructor-throws-an-exception/32323458) – Yastanub Mar 28 '19 at 13:37
  • Is this a question about Asan, presense of memory leaks or their prevention? – yugr Mar 28 '19 at 14:00
  • 1
    If your constructor allocates something, and throws an exception, it is your constructor's duty to deallocate that thing. Otherwise everything will mess up. You can't rely on the destructor, since logically the destructor can only be called on completely constructed objects, and the object cannot be counted as "completely constructed" if the constructor does not finish normally (i.e. throws.) – L. F. Mar 28 '19 at 14:05

1 Answers1

2

The following part of the code is invalid:

int main()
{
    A *a;
    try { a = new A; }
    catch(int) { delete a; } // AddressSanitizer: SEGV on unknown address
}

If exception is thrown while running new A, then anything A has manage to construct, before the exception, is destructed. Also, the memory of a is freed automatically.

In the above case, when an exception is thrown, the pointer a is not even assigned once and is left uninitialized.

The safest way around your leak is to use std::unique_ptr.

class A
{
    std::unique_ptr<int> x;
public:
    A (): x(std::make_unique<int>()} { throw 0;}
    A(A&&) = default;
    A& operator=(A&&) = default;
    A(const A &); // do something smart here
    A& operator=(const A &); // do something smart here
    ~A () { }
};

With a unique_ptr anything constructed before the exception will be freed automatically.

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33