trouble with pointers

i was told here recently, that something like this:

1
2
3
4
char *pointer;

delete pointer;
pointer=new char[x];


is very-very bad and dangerous.

How do i know if this pointer was already assigned?

something like:

1
2
pointer=new char[x1];
pointer=new char[x2];


crashes compiler.

Need a function which could define if pointer was already assigned, and if needed - delete it.
1
2
pointer=new char[x1];
pointer=new char[x2];
As long as pointer, x1, and x2 are defined, that will compile; and as long as both x1 and x2 have reasonable values, the program will work. There will be a memory leak, yes, but the program won't crash.

The usual, if not only, method to know whether a pointer points to something valid is by assigning it to zero when it doesn't. If the pointer has any other value, it's assumed that it can be safely dereferenced. However, that's about all the information you can get from a pointer's value. It's impossible to know whether a pointer points to something that can or should be freed, or how it should be freed.
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void f(int *&p){
    if (p)
        delete p;
    pointer=new int(0);
}

//...
int *p=0;
f(p); //OK
p=new int;
f(p); //OK
p=new int[10];
f(p); //Memory leak.
int a;
p=&a;
f(p); //Very bad! Will try to delete a pointer to the stack! 
1
2
3
4
5
6
void f(int *&p){
    if (p)
        delete p;
    pointer=new int(0);
}


I see this check for if(p) often and it is useless. If p != NULL and not valid the program will crash!
And if p == NULL then nothing will happen since delete NULL; is valid.
1
2
3
4
char *pointer;

delete pointer;
pointer=new char[x];


The problem with that is that you delete pointer before it has been given a meaningful value. It will not automatically be set to zero when you create it. So it will contain some completely unknown, random value.

Calling delete on that value could cause a crash and/or corrupt other program data.

You should only delete a pointer that is explicitely set to zero or that has been given a value allocated by new:


1
2
3
char *pointer = 0;

delete pointer; // good!! 



1
2
3
char *pointer = new char[256];

delete[] pointer; // good!! 


Notice also then when you delete a pointer you need to specify if it was pointing to an array or just a single charatcer.


The rule is that if you call new, then you call delete, but if you call new[] then you must call delete[].

1
2
3
4
5
char* p = new char; // allocate one char
delete p; // Good, deleted the single char

p = new char[256]; // allocate an array of chars
delete[] p; // Good, deleted the whole array 





RedX wrote:
I see this check for if(p) often and it is useless. If p != NULL and not valid the program will crash!
And if p == NULL then nothing will happen since delete NULL; is valid.

What?
What?

The check is useless because it doesn't protect against p being a dangling pointer and is redundant if p is 0.
If p != NULL and not valid the program will crash!
Why would it crash?

And if p == NULL then nothing will happen since delete NULL; is valid.
If p == NULL, delete p will not execute.
@blackcoder
It would crash since you are trying to free a random piece of memory (segfault). It must not crash, but it probably will.
Take a look at this. I implemented a smart pointer that is aware of the 'kind' of memory it holds (i.e. static or dynamic) and deallocates it by itself when necessary. Of course more work needs to be done here, I plan on also making it aware of the number of smart pointer instances that hold the same dynamic address and only delete it when the last of them expires. I'll have to also overload the = operator ofc... This is just a simple demonstration of the memory 'kind' awareness and auto-deletion.

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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#include <iostream>
using namespace std;

/**************************************************/
//These things here are for casting purposes...
template <typename T>
class DynamicPointer
{
    public:
    T *ptr;
    DynamicPointer(T * p):ptr(p) {}
};

template <typename T>
class StaticPointer
{
    public:
    T *ptr;
    StaticPointer(T * p):ptr(p) {}
};

template <typename T, unsigned int S>
class DynamicArray
{
    public:
    T *ptr;
    DynamicArray(T * p):ptr(p) {}
};

template <typename T, unsigned int S>
class StaticArray
{
    public:
    T *ptr;
    StaticArray(T * p):ptr(p) {}
};
/**************************************************/

//Our smart pointer class
template <typename T>
class SmartPointer
{
    private:
    T * pointer;
    unsigned int size;
    bool dynamic;

    static T foo;

    inline bool must_free() {return dynamic && pointer;}

    void mem_free()
    {
        cout << "mem_free() called!" << endl;
        if (size>1) {delete[]pointer; cout <<"deleted the previous array!" << endl;}
        else {delete pointer; cout << "deleted the previous pointer!" << endl;}
        pointer=0;
    }

    public:
    SmartPointer():pointer(0),size(0),dynamic(false) {}
    ~SmartPointer()
    {
        if (must_free()) mem_free();
    }

    void operator=(DynamicPointer<T> dp)
    {
        if (must_free()) mem_free();

        pointer=dp.ptr;
        size=1;

        dynamic=true;
    }

    void operator=(StaticPointer<T> sp)
    {
        if (must_free()) mem_free();

        pointer=sp.ptr;
        size=1;

        dynamic=false;
    }

    template <unsigned int S>
    void operator=(DynamicArray<T,S> dp)
    {
        if (must_free()) mem_free();

        pointer=dp.ptr;
        size=S;

        dynamic=true;
    }

    template <unsigned int S>
    void operator=(StaticArray<T,S> sp)
    {
        if (must_free()) mem_free();

        pointer=sp.ptr;
        size=S;

        dynamic=false;
    }

    T & operator[](unsigned int i)
    {
        if (i>=size || pointer==0)
        {
            cerr << "no, you don't want to do that!...\n";
            return foo;
        }

        return *(pointer+i);
    }

    T & operator*()
    {
        if (pointer==0)
        {
            cerr << "no, you don't want to do that!...\n";
            return foo;
        }

        return *(pointer);
    }

};

template <typename T>
T SmartPointer<T>::foo;

//Let's see what it can do...
int main()
{
    SmartPointer<int> spint;

    cout << "assigning a dynamic pointer..." << endl;
    spint=DynamicPointer<int>(new int);

    *spint=4;
    cout << *spint << endl;

    cout << "\nassigning a static pointer..." << endl;

    int x;
    spint=StaticPointer<int>(&x);

    *spint=5;
    cout << *spint << endl;

    cout << "\nassigning a dynamic array..." << endl;

    int i;
    spint=DynamicArray<int,3>(new int[3]);

    for (i=0; i<3; i++)
    {
        spint[i]=i+1;

        cout << "spint[" << i<< "]=" << spint[i] << endl;
    }

    cout << "\nassigning a static array..." << endl;

    int arr[2];
    spint=StaticArray<int,2>(arr);

    for (i=0; i<2; i++)
    {
        spint[i]=2-i;

        cout << "spint[" << i<< "]=" << spint[i] << endl;
    }

    //just to verify that mem_free() is NOT called
    //for the static array...
    spint=StaticPointer<int>(&x);

    return 0;
}

Last edited on
I see this check for if(p) often and it is useless. If p != NULL and not valid the program will crash!
And if p == NULL then nothing will happen since delete NULL; is valid.
The explicit check served the purpose of illustrating my point better than just deleting the pointer. Otherwise, I would have depended on OP knowing that behavior.

m4ster r0shi: Well, that's the most useless thing ever. The point of smart pointers is automatic resource management. Why would anyone want a smart pointer that points to things that don't need to be managed?
helios wrote:
Why would anyone want a smart pointer that points to things that don't need to be managed?

Bounds checking?
Last edited on
Now you're entering the point when you shouldn't be using be pointers anymore, and should be using vectors instead.
helios wrote:
Now you're entering the point when you shouldn't be using be pointers anymore, and should be using vectors instead.

No, I don't think so.

If I want static memory allocation and bounds checking I'll use a smart pointer. If I want dynamic memory allocation and bounds checking I'll use a smart pointer again. I'll only use a vector if I want dynamic memory allocation, bounds checking and resizability.

Look. A smart pointer by definition is something that can be used as a pointer but also provides some additional features. One of them can be automatic memory management, another can be bounds checking and you can add here anything you think might be useful...

EDIT: Sorry I couldn't help it...

helios wrote:
Well, that's the most useless thing ever.

You're the most useless thing ever :'D

(watch here -> http://www.youtube.com/watch?v=qOTNdxOKZiQ from 0:00 to 0:13)
Last edited on
Sorry, but that is useless not from the conceptual point of view but from the practical. You are reinventing the wheel (if understood it properly) why not just use boost/C++0x shared_pointer and weak_pointer?
I am aware of both auto_ptr and boost smart pointers. I did this for educational purposes.

EDIT: Also, I'm not sure that these smart pointers offer the bounds checking functionality for static arrays (correct me if I'm wrong) so, in that case, I'll have to reject your argument too.
Last edited on
They don't implement bounds checking for reasons of performance. The idea is to make auto_ptr and the various
smart pointers equal in performance to a raw pointer. This is doable for the access case (but bounds checking
is impossible) but not for the create/delete case since reference counts need to be bumped.

Topic archived. No new replies allowed.