cancel destructor calls in operator delete[]

Apr 18, 2014 at 9:06pm
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.
Apr 18, 2014 at 9:16pm
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 Apr 18, 2014 at 9:16pm
Apr 18, 2014 at 9:20pm
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 [].
Apr 18, 2014 at 9:24pm
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 Apr 18, 2014 at 9:29pm
Apr 18, 2014 at 9:32pm
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.
Apr 18, 2014 at 9:41pm
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 Apr 18, 2014 at 9:42pm
Apr 18, 2014 at 9:44pm
Ok, I will look into what valgrind does. What' an allocation function? Wouldn't that be the operator new?
Apr 18, 2014 at 10:08pm
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.
Apr 18, 2014 at 10:21pm
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)
Apr 18, 2014 at 10:26pm
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.
Apr 18, 2014 at 10:30pm
Thanks, marking as solved.
Apr 18, 2014 at 10:31pm
@Disch did you compile and run?
Apr 18, 2014 at 10:35pm
@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 Apr 18, 2014 at 10:37pm
Topic archived. No new replies allowed.