delete[] object causes crash!!!

Hello. I made a dynamic array of objects. When i call delete[] , program crashes and stops responding. But it does strange behavior: look at this code and output.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//main file
#include "myobject.h"

int size;
myObject *foo;

//some operations to estimate size

foo = new myObject[size];

//some operations with myObject

std::cout<<"size: "<<size<<"\n";
std::cout<<"Deleting object\n";

size=0;
delete [] foo;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//myobject.h

class myObject
{
    public:
    int number;

    Object1 ob1[64]
    Object2 *ob2;

    myObject(){ };
    ~myObject()
    {
        std::cout<<"delete "<<number<<"\n";

        delete [] ob1;
        delete [] ob2;
    };
}


And the strange output:

size: 11
Deleting object
delete 10
delete 9
delete 8
delete 7
delete 6
delete 5
delete 4
delete 3
delete 2
delete 1
delete 0


And then it crashes and stops responding.
But it does strange behavior:

Your code has what we call "undefined behavior." It could do anything.

Don't delete[] stuff you don't allocate with new[].
But the problem is that i allocated everything.
But the problem is that i allocated everything.
Nope, line 16: ob1 is not allocated with new[]
ob1 and ob2 are allocated during the process i have not shown
Object1 ob1[64]
assuming you're just not showing the ";" either.

Here you have created an array of 64 Object1 called ob1 on the stack. It cannot be deallocated using "delete []"

I don't see how you can claim to have legally allocated it elsewhere.

In any case, since it's a major point, please show the "process" that allocates it.
there is a
;
symbol after that declaration, i just forgot to write it here. Also, the process where i allocated it is inside a for loop, its long, so i won't write it here. But it goes through all array and assigns a value to every element.
Also, ob1 and ob2 are structs, not classes.
Last edited on
ob1 and ob2 are allocated during the process i have not shown


If you're having problems with allocation/deallocation and you want our help with it, we're going to have to see what you're doing. We can't tell you what's going wrong when you don't show us relevant code.

Also, the process where i allocated it is inside a for loop, its long, so i won't write it here. But it goes through all array and assigns a value to every element.


Every new[] must have a matching delete[]
Every new must have a matching delete.

If you are allocating individual elements with new in a loop, then you must delete those individual elements with delete in a loop.




Either that or just use smart pointers so you don't have to deal with any of this crap.
it goes through all array and assigns a value to every element

assigning a value is not the same thing as allocating memory using new

ob1 and ob2 are structs, not classes

What's the difference between a struct and a class? Why have you brought it up?
Last edited on
This code is just like the first one, however, it doesn't crash. So even if i delete something that hasn't been allocated with "new", it works.

This code:
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 <iostream>
#include <fstream>
#include <string>

using namespace std;

struct Kuprine
{
    int knyg;
};

class Mokinys
{
public:
    int num;
    Kuprine *kupr;
    Kuprine kup2[4];

    Mokinys()
    {

    }
    ~Mokinys()
    {
        cout<<num<<endl;
        delete [] kupr;
        delete [] kup2;
    }
};

int main()
{
    Mokinys *mok;

    int size=5;

    mok=new Mokinys[size];

    for(int i=0; i<size; i++)
    {
        mok[i].num=i;

        for(int j=0; j<4; j++)
        {
            mok[i].kup2[j].knyg=j;
        }
    }

    delete [] mok;

    return 0;
}
So even if i delete something that hasn't been allocated with "new", it works.


You're wrong.

If you delete something that wasn't allocated with new, behavior is undefined. It might "work", or it might crash. There's no way to know.

One thing you can know is that you should never, ever, ever do it.



EDIT

in this example:

1
2
3
4
5
6
7
// lines 26,27:
        delete [] kupr;  // <- not allocated with new[]  BAD BAD BAD DON'T DO THIS EVER
        delete [] kup2;  // <- ditto


// line 49
delete [] mok;  // <- allocated with new[].  So this is Correct! 
Last edited on
Youre right. That program crashed another time when called. So i decided to do checking before delete[]ing. At first i set all arrays to NULL. Then check.
if(arr!=NULL) delete [] arr;
But there's another problem:
1
2
arr=NULL;
if(arr!=NULL) delete [] arr;

But when i do the final destruction with checking if it is NULL, it starts deletion, even if the pointer was set to NULL!!! And it causes crash again!!! I don't know which magic processes makes the pointer not NULL. Any ideas?

Last edited on
deleting a null pointer is harmless. It effectively does nothing. It's totally safe.

1
2
3
int* foo = nullptr;
delete foo;  // <- safe.  Will not crash the program.  Will not do anything bad.
    // (will not do anything at all) 


But when i do the final destruction with checking if it is NULL, it starts deletion, even if the pointer was set to NULL!!! And it causes crash again!!! I don't know which magic processes makes the pointer not NULL. Any ideas?


You are overthinking this.

Null/not-null has absolutely nothing to do with it.


Does the pointer point to something allocated with new[]?
- If yes, then delete[] it.
- If no, then don't delete[] it.

It's that simple.

If you use new[] to allocate something, then you use delete[] to clean it up.
If you don't use new[], then you must not use delete[].


There's really nothing more to it.
Last edited on
It would really help if you showed more code.

arr=NULL;
if(arr!=NULL) delete [] arr;


Where you do this matters, that's why I'm asking you to show more code. If for example you're doing this anywhere other than in your destructor, then your destructor is still going to do
delete [] kupr;
delete [] kup2;
anyway.

Assigning NULL to a pointer doesn't free the memory it points to, you've just leaked that memory most likely. Neither does deleting a pointer assign null to it. It's still holds the address of memory you no longer own.

You may want to assign NULL to a pointer after deleting it, as a way of checking in future whether it's been released or not.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
int *x = new int[100];
...
delete [] x;
x = nullptr;
...

// in some other context that's aware of x
if (x)
{
// use x
}
else
{
// x is null, so we know it's been released, but this is up to the programmer to enforce, not the implementation
}

Have you considered using shared_ptr instead of this raw pointer business?
Last edited on
That is the point, i set that pointer to null after deleting[] it.
That is the point, i set that pointer to null after deleting[] it.


Are you sure you are supposed to have deleted it?

I'm still not convinced you grasp the core concept here. Can you post your code?
Thats my original code, where i use that problematic pointer. Im making a game which creates a world and writes it to file.

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
//world.h

class World
{
protected:
    long playerX=0;
    long playerY=0;

    int newChunkCount=0;

    Chunk *newChunks=NULL; //Thats the pointer
    Tile *tiles=NULL;
    Entity *entities=NULL;

public:
    World();
    ~World();

    int create(std::string name, uint8_t world_mode, uint8_t difficulty, long startX=0, long startY=0);

    void generateTiles(Chunk &chun);

    int saveChunksToFile(int mode=1);

    int generateChunks(long X, long Y, int howMany_X, int howMany_Y);
};


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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//world.cpp

World::~World()
{
    if(tiles) delete [] tiles;
    if(entities) delete [] entities;
    if(newChunks) delete [] newChunks;
}

int World::create(std::string name, uint8_t world_mode, uint8_t difficulty, long startX, long startY)
{
    //some code

    std::cout<<"Generating chunks \n";

    generateChunks(playerX, playerY, 4, 2);

    std::cout<<"saving chunks \n";

    if(saveChunksToFile()==-1) return -1;

    return 0;
}

int World::saveChunksToFile(int mode)
{
    std::cout<<"save chunks: opening ofstream \n";

    std::ofstream outp(filename2.c_str(), std::fstream::app);

    if(!outp.is_open()) return -1;

    std::cout<<"start loop \n";

    for(int i=0; i<newChunkCount; i++)
    {
        std::cout<<"outp header \n";

        outp<<" #chnk "<<newChunks[i].X<<" "<<newChunks[i].Y<<" "<<newChunks[i].how_many_entities<<" ";

        std::cout<<"posting chars \n";

        for(int j=0; j<64; j++)
        {
            outp<<char(newChunks[i].tiles[j].type)<<" ";
        }
        outp<<" #ents ";

        std::cout<<"entities \n";

        if(newChunks[i].how_many_entities>MAX_ENTITIES) newChunks[i].how_many_entities=MAX_ENTITIES;

        for(int j=0; j<newChunks[i].how_many_entities; j++)
        {
            outp<<newChunks[i].entities[j].active<<" ";
            outp<<char(newChunks[i].entities[j].Chunk_X)<<" ";
            outp<<char(newChunks[i].entities[j].Chunk_Y)<<" ";
            outp<<char(newChunks[i].entities[j].type)<<" ";
        }
        outp<<"\n ";

        std::cout<<"1 chunk posted \n";
    }
    std::cout<<"closing \n";

    outp.close();

    std::cout<<"size: "<<newChunkCount<<"\n";
    std::cout<<"deleting newChunks \n";

    newChunkCount=0;
    if(newChunks)
    {
        delete [] newChunks;
        newChunks=nullptr;
    }

    return 0;
}

int World::generateChunks(long X, long Y, int howMany_X, int howMany_Y)
{
    int ix, iy, i, am=0;

    Coordinate coord[4*howMany_X*howMany_Y];

    for(iy=Y-howMany_Y; iy<Y+howMany_Y; iy++)
    {
        for(ix=X-howMany_X; ix<X+howMany_X; ix++)
        {
            if(!checkChunk(ix,iy))
            {
                coord[am].x=ix;
                coord[am].y=iy;

                am++;
            }
        }
    }

    if(am==0) return 1;

    newChunkCount=am;

    if(newChunks) delete [] newChunks;

    newChunks=new Chunk[newChunkCount]; //creating that pointer

    for(i=0; i<am; i++)
    {
        newChunks[i].X=coord[i].x;
        newChunks[i].Y=coord[i].y;
        newChunks[i].how_many_entities=0;
        newChunks[i].number=i;

        generateTiles(newChunks[i]);
    }

    populateNewChunks();

    //if(saveChunksToFile()==-1) return -1;

    return 0;
}
Wow! It works now. I just fixed the issue! There were other pointers which were causing this issue. Now its fine.
Topic archived. No new replies allowed.