7

I'm new to C++ and i'm not absolutely sure how to deal with arrays and pointers in a safe way. In my class I got a member called items:

Item * items;

in my class method called read() I open a file and read the items from this file. I allocate the space accordingly:

items = new Item[item_count];

item_count is given as a variable in the file and is read in advance before creating any items. In the deconstructor in my class I release the memory like this again:

delete[] items;

But if i call the method read() twice before my deconstructor is executed the memory for the first array will not be released properly. I would like to release it in the read method in advance before allocating new memory. But how do I check if some memory is already allocated for the array items?

EDIT: I know there are many other possibilities out there with more 'modern' approachs and more comfortable solutions. But in this case we where explicitly told to use pointers and arrays (education purpose only).

little_planet
  • 1,005
  • 1
  • 16
  • 35
  • `save way` or did you mean `safe way`? also, this is not `C`. – Sourav Ghosh Jun 25 '15 at 15:13
  • 4
    Use `std:vector`. Never use raw pointers. – Rob K Jun 25 '15 at 15:14
  • 1
    @RobK certainly for most situations you don't need pointers, but they are sometimes the best solution, even in c++, although c++ programmers try to avoid them, they are not completely avoidable, and you can learn to work with them and be good at that too. – Iharob Al Asimi Jun 25 '15 at 15:17
  • @RobK - while that advice is okayish, it's entirely inappropriate in many circumstances, including inexpensive micro-controllers. _Never_ is a little too strong and generalized imho. Raw pointers are fine - it's just that many dont have sufficient nous to work with them, hence the proliferation of managed languages and the like. Raw pointers are like many things - perfectly acceptable and appropriate given the right circumstances. :) - _EDIT:_ beaten to it by iharob. – enhzflep Jun 25 '15 at 15:19
  • 2
    @enzhflep you may be right, but IMHO a beginner should first get used to RAII and only then he is ready to encounter the "right circumstances" where raw pointers are appropriate. Maybe "never" is too strong, but it goes into the right direction ;). Advising beginners that ask for raw pointers not to use them is imho always a good idea. – 463035818_is_not_an_ai Jun 25 '15 at 15:29
  • 1
    I thought about caveating my statement, but decided not to. This guy is obviously a noob. He's surely not programming micro-controllers. For him, at this time, he should never be using raw pointers. – Rob K Jun 25 '15 at 15:32
  • Rob's right. You wouldn't tell a 30-year veteran of the industry who's programming spaceships "never use raw pointers", but that's not at all what's going on here. – Lightness Races in Orbit Jun 25 '15 at 15:45

3 Answers3

8

In modern C++, "the safe way" is to avoid raw pointers and raw arrays entirely.

Declare your variable like this:

std::vector<Item> items;

Allocate the space like this:

items.resize(item_count);

In the deconstructor in your class, no code is necessary to release this memory. It's handled automatically.

The reuse of items that you describe in your question will work.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
  • 1
    The safe way is not to drive cars because car accidents are very frequent and many of them are deadly. – Iharob Al Asimi Jun 25 '15 at 15:22
  • 3
    @iharob that is correct, if I'm following your analogy correctly. Asking, in general, how to drive a car safely is far too broad a question. And a car was never needed here in the first place. – Drew Dormann Jun 25 '15 at 15:29
  • 1
    i think this discussion just got a bit out of hand. I have a reason to use arrays and pointers in this way: because we are told to do so (sorry for not making this more clear in advance). I already know that there are other possibilities. But because there are many programs left which are coded in this way i have to know how to deal with them. Thank you very much for your help anyway. – little_planet Jun 25 '15 at 15:32
  • @little_planet no need to apologize. You may still edit your question now to make the parameters more clear. – Drew Dormann Jun 25 '15 at 15:33
6

Unless you have some strong reason not to do so, just use std::vector for arrays in C++:

#include <vector>  // for std::vector

....
std::vector<Item> items;

In this way, you don't have to explicitly call delete[] to release vector items' resources; it's just done automatically thanks to vector's (and Items') destructors.

This helps building code that is structurally incapable of leaking resources.


You can create a vector of itemCount Items using something like:

std::vector<Item> items(itemCount);

or you could dynamically resize the vector using its resize() method, e.g.:

items.resize(itemCount);
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • 1
    This involves copy operations that the OP might not want. – Iharob Al Asimi Jun 25 '15 at 15:20
  • 3
    @iharob: the OP might be more specific about that in his request (in fact, I also wrote "unless you have some strong reason not do so"). Anyway, it's sufficient that OP's Item is a movable class; or he could use `vector>`. – Mr.C64 Jun 25 '15 at 15:22
  • That's one of the ugly things in c++, you can't wite `vector>` because then it's ambigous whether `>>` is the right shift operator or just to consecutive `>`s, so you mean `vector< unique_ptr >`, notice the space befor `unique_ ...`, it's because otherwise it wouldn't look consistent, it's ugly isn't it? – Iharob Al Asimi Jun 25 '15 at 15:24
  • 5
    @iharob: Are you still in C++98 mode? The `...>` syntax is perfectly valid in **C++11/14.** – Mr.C64 Jun 25 '15 at 15:26
  • Oh, also. Normally programmers learning c++ are not aware of the fact of the possible unecessary copy opeartions, so you have to be a skilled c++ programmer to know the `unique_ptr` thing, which I didn't know. – Iharob Al Asimi Jun 25 '15 at 15:26
  • No, I don't write c++ code, because I don't like c++, but It's good to know that, because it really forced inconsistencies in code. – Iharob Al Asimi Jun 25 '15 at 15:27
  • 4
    @iharob, if you don't like C++ then why are you answering and commenting on questions about it? – Rob K Jun 25 '15 at 15:36
  • The question was initially tagged c, check my edit. And I wanted to answer because I know the **answer to the question**, I am not telling the OP about the exciting c++ features which are precisely the reason I hate it for. – Iharob Al Asimi Jun 25 '15 at 15:38
  • @iharob: When I wrote my answer, I only found the [c++] and [arrays] tags. I've just noted that _after_ several minutes I wrote my answer, the OP added an EDIT like _" [...] But in this case we where explicitly told to use pointers and arrays (education purpose only)."_ – Mr.C64 Jun 25 '15 at 15:41
2

In c, normally you initialize the pointer to NULL so you can check whether or not it points to valid memory, and then after deallocation you immediately set it back to NULL.

Failing to do so, may cause problems, like dereferencing an already deallocated pointer (they're called dangling pointers), so you must be careful.

In c++ you should use nullptr which is equivalent to c's NULL.

Also, there are smart pointers in c++, i.e. pointers that can do this automatically.

Edit: (the answer above was edited) as suggested from the comments, and although this same idea is correct, you should not use NULL in c++, instead use nullptr which has the same functionality, but takes care about the fact that in c++ void * is not automatically converted to any other pointer type like in c.

This Stack Overflow Answer has the details, and also an example that would definitevely convince you and me to use nullptr instead.

Community
  • 1
  • 1
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • I see. So i just set `items = NULL` in my class, check if it is still `NULL` in the read method and otherwise deallocate the memory first. – little_planet Jun 25 '15 at 15:23
  • @little_planet something like that, yes. – Iharob Al Asimi Jun 25 '15 at 15:25
  • 8
    `NULL` is strongly discouraged. `nullptr` is better. Even better is to use a `unique_ptr` and not worry about anything. – nwp Jun 25 '15 at 15:28
  • 2
    I don't know the difference and I am not interested in it, the idea in my answer is correct, how to achieve that in c++ is something else, I limited my answer to the question, whether it's `NULL` or `nullptr` which seems to me like a unecessary construct even if I don't know what it means, still if it's the c++ way you can leave the comment as you did so the OP can follow it. It's that the c++ language introduces new things this beating it's original purpose to be 100% compatible with c. – Iharob Al Asimi Jun 25 '15 at 15:30
  • @little_planet as you can see the answer has been massively downvoted because of I used `NULL`, which is simply `(void *) 0` I suppose that `nullptr` does take care of the fact that in c++, `void *` is not automatically converted to any other pointer type but instead it requires an explicit cast, so may be you can use `nullptr` isntead, but I am no expert in that matter, the idea is still valid, even if c++ programmers like to write inefficient code by using classes that force unecessary copying just because they are afraid of pointers apparently. – Iharob Al Asimi Jun 25 '15 at 15:33
  • And now I can't even delete it because it was accepted. And it's the correct answer as anyone can see from [this comment](http://stackoverflow.com/questions/31054242/c-safe-array-deletion/31054465?noredirect=1#comment50130621_31054465) – Iharob Al Asimi Jun 25 '15 at 15:34
  • I'm not down voting it - it answers the original question instead of explaining why the question itself was wrong - keep it :p – Andy Newman Jun 25 '15 at 15:36
  • @iharob you just triggered some c++ purists! But seriously, you have the answer to op's question, as he probably doesn't even know how to use stl containers. – asdfasdf Jun 25 '15 at 15:36
  • 1
    Since this is for education, the typical pattern is to always set to 0 after deleting, and to delete before allocating. Deleting a null ptr is safe so you don't need to check. – Andy Newman Jun 25 '15 at 15:38
  • 5
    Well at least you're not being harmfully stubborn. Not sure where a "language war" about C comes into it, either?? You got downvoted because your advice is archaic and dangerous. Try to remember why we're here. – Lightness Races in Orbit Jun 25 '15 at 15:46
  • All you need to do is tweak the answer so that it does not promote outdated practices, and it'll be fine. N.B. I'm not saying write an answer about `std::vector` because you're right about one thing: this question is not about the use of `std::vector`. And those other answers should be comments. – Lightness Races in Orbit Jun 25 '15 at 15:48
  • @LightnessRacesinOrbit you are absolutely right, I just fixed the points that promoted outdated practices, as you said. – Iharob Al Asimi Jun 25 '15 at 15:58
  • 2
    @iharob just wqnna note that `NULL` isn't a `void *`. It's exactly `#define NULL 0` in C++. The problem is that if a function got an int and pointer overload it calls the int one, even though you'd expect the pointer one for `NULL`. `nullptr` is a pointer type, not a macro and fixes it. – AliciaBytes Jun 25 '15 at 16:13
  • @RaphaelMiedl I see, that makes sense, because otherwise comparisons would complain about the fact that `void *` is incomaptible with the actual pointer type. – Iharob Al Asimi Jun 25 '15 at 16:39
  • 4
    BTW this is complete nonsense: _"It's that the c++ language introduces new things this beating it's original purpose to be 100% compatible with c."_ – Lightness Races in Orbit Jun 25 '15 at 16:47