cancel destructor calls in operator delete[]

Let's start with something from the c++ reference:

... delete[] is an operator with a very specific behavior: An expression with the delete[] operator, first calls the appropriate destructors for each element in the array (if these are of a class type) ...


I was wondering if I can tell delete[] to not call destructors, for example if I already know that the delete[] statement should be delete without []. That would be very useful for memory management/memory leak detection.
There seems to be a misconception.

you use delete[] when you new[]
you use delete when you new

The brackets have nothing to do with destructors. Both delete and delete[] will invoke the destructor(s) of the object(s) they're deleting.

Why wouldn't you want to call a destructor anyways?
Last edited on
My intention is to not call the destructor. In a memory leak detector, I want to generate an error message instead of a segfault when delete[] is used on a pointer where memory was allocated using new without [].
A delete[] expression cannot become "delete without []". They are different expressions that do different things and cannot be mixed. Destructor calls are only a part of it.

If you want to manage memory, then do so through allocators, where allocation, construction, destruction, and deallocation are four separate actions, or in some equivalent manner.

(edit: didn't see the last update.. as a quick hack, you could replace the allocation functions. For a serious new vs delete[] analysis, look at how valgrind operates)
Last edited on
Thanks, I know that I must not mix delete and delete[]. The idea is to catch that error and display a warning instead of a segfault. An allocator is probably what I would need. In my case it's too much effort for a memory leak detector. I guess I'll have to live with the segfaults. Thanks again for helping.
here's a very raw proof-of-concept of the "quick hack" I mentioned

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <set>
#include <iostream>
#include <cstdlib>

class NewDeleteMismatchDetector {
    static std::set<void*> nonarrays;
    static std::set<void*> arrays;
 public:
    static void* operator new(std::size_t sz)
    {   
        return *nonarrays.insert(::operator new(sz)).first;
    }
    static void* operator new[](std::size_t sz)
    {   
        return *arrays.insert(::operator new[](sz)).first;
    }
    static void operator delete(void* ptr)
    {   
        if(nonarrays.erase(ptr)) {
            ::operator delete(ptr);
        } else {
            std::cerr << "attempting to delete a pointer that was not allocated with new\n";
            std::abort();
        }
    }
    static void operator delete[](void* ptr)
    {   
        if(arrays.erase(ptr)) {
            ::operator delete[](ptr);
        } else {
            std::cerr << "attempting to delete[] a pointer that was not allocated with new[]\n";
            std::abort();
        }
    }
};
std::set<void*> NewDeleteMismatchDetector::nonarrays;
std::set<void*> NewDeleteMismatchDetector::arrays;

class Foo : public NewDeleteMismatchDetector
{
};

int main()
{
    Foo* f = new Foo;
    delete f; // ok

    Foo* f2 = new Foo[10];
    delete[] f2; // ok

    Foo* f3 = new Foo[10];
    delete f3; // abort
}
Last edited on
Ok, I will look into what valgrind does. What' an allocation function? Wouldn't that be the operator new?
Read your code and it doesn't seem to solve my issue. Overwriting the global operators new and delete[] doesn't help the destructors being called on statement delete[]. Defining them for a class shouldn't make a difference here. If I modify your class Foo

1
2
3
4
5
6
7
8
class Foo : public NewDeleteMismatchDetector
{
    int* pi;

public:
    Foo() { pi = new int; };
    ~Foo() {int i = *pi /*segfault here*/; delete pi; };
};


and

1
2
3
4
5
6
7
8
9
10
11
int main()
{
    Foo* f = new Foo;
    delete f; // ok

    Foo* f2 = new Foo[10];
    delete[] f2; // ok

    Foo* f3 = new Foo();
    delete[] f3; // slightly changed this
}


the operator delete[] for Foo* f3 is not called before the destructor for all elements, dereferencing the member pi.
Overwriting the global operators new and delete[] doesn't help the destructors being called on statement delete[].

I don't follow.
delete[] calls the destructors for the same reason 2+2 performs addition - that's what it does. It can't be changed.

I was only showing how one could "generate an error message when delete[] is used on a pointer where memory was allocated using new without []".

(tools like valgrind or purify of course do that and more without changing your source code)
I'm a little confused.

1
2
3
4
5
6
7
8
class Foo : public NewDeleteMismatchDetector
{
    int* pi;

public:
    Foo() { pi = new int; };
    ~Foo() {int i = *pi /*segfault here*/; delete pi; };
};



That wouldn't segfault. If cubbi's example didn't solve your problem, I'm still lost as to what your problem actually is.
Thanks, marking as solved.
@Disch did you compile and run?
@Disch did you compile and run?


Not at first, no.

But I did just now to be sure and it works fine just as I expected.


EDIT:


oooooooohhh... wait .... I see what you're saying. I didn't try it with the delete[] change you made. I see what you're asking now.
Last edited on
Topic archived. No new replies allowed.