views:

100

answers:

4

Hi,

Looking for some help with arrays and pointers and explanation of what I am trying to do. I want to create a new array on the heap of type Foo* so that I may later assign objects that have been created else where to this array. I am having troubles understanding what I am creating exactly when I do something like the following.

Foo *(*f) = new Foo*[10];

Also once I have created my array how do I access each element for example.

(f + 9)->fooMember(); ??????

Thanks in advance.

A: 

You can create an array of pointers using the following code:

Foo** f = new Foo*[10];

Then access the elements with:

f[9]->fooMember();

Be sure to clean up afterwards:

delete[] f;

Thanks.

beta
All correct, and yet I am missing a comment on the fact that if those three lines are pasted together into a program with no extra code the system will most probably die (as no actual `Foo` objects were created)
David Rodríguez - dribeas
+3  A: 
Foo *(*f) = new Foo*[10];

The parentheses in the declaration are unnecessary, so this is the same as:

Foo **f = new Foo*[10];

In any case, the new Foo*[10] allocates space for ten Foo*s and leaves them uninitialized. It returns a pointer to the initial Foo* in the array (the zeroth element), which you assign to f.

To access elements of the array, you simply use subscripting:

f[0] = new Foo;
f[0]->fooMember();

Remember that anything you create using new[] must be freed once when you are done with it by calling delete[] on the pointer. For example:

delete[] f;

This does not delete the elements pointed to by the Foo*s in the array. If you create Foo objects using new, you must delete them before you delete the array. For example, to free the element we created above:

delete f[0];
James McNellis
Thank you. If I wanted to access the individual elements without using the [] operator but with pointer arithmetic how would this look?
Thomas
@Thomas: `f[0]` is just shorthand for `*(f + 0)`, so for example, you can do `(*(f + 0))->fooMember()`.
James McNellis
@James McNellis: Thanks. What roll does the first brackets with * play?
Thomas
@Thomas: The opening paren causes the dereference-and-child operator `->` to operate on the *object* as opposed to the pointer. Just like the rest of pointer logic, it's confusing as heck at times.
Christian Mann
@Thomas: why don't you want to use the square brackets? They are there for a reason: simplifying the code when you perform random access into arrays.
David Rodríguez - dribeas
+1  A: 

When you have this situation, you might find the following code snippet useful:

First the initialization:

Foo** f = new Foo*[10];
for (int i = 0; i < 10; i++) {
    f[i] = new Foo;
}

Then to access each element in the f array which is what you asked, but you won't be able to do so unless you allocate memory properly for each member by calling the constructor as done above:

f[9]->fooMember();

Finally, to keep things tidy and to prevent memory leaks:

for (int i = 0; i < 10; i++) {
    delete f[i];
}
delete[] f;
Khnle
You should use `std::for_each` over explicitly written loops.
Billy ONeal
@Billy ONeal - That's assuming you're going to use STL. Granted that's almost always true, still that's an assumption. The for loop is still legal and valid C++.
Khnle
@Khnle: True. However, just because something's possible or valid does not mean it's the best method for accomplishing things. Algorithm calls are always better than explicit loops.
Billy ONeal
@Billy ONeal: can you write the equivalent `for_each` calls? Is the code going to be any simpler or more complex than the plain `for` loop? I tend to use the simplest approach, the one that leaves with the easier to read code, and to be fair I would have to think on how to write those two `for_each` calls... so I guess that ease of writing also affect my decisions on what to write. In this particular case I would do just as Khnle has done.
David Rodríguez - dribeas
@Billy I can only say - b*ll*cks.
anon
@Billy: I _might_ use `for_each` once we have C++0x and either (a) lambda functions or (b) `default_delete`; until then, though, a for-loop is the way to go.
James McNellis
+1  A: 

Arrays and pointers aren't very C++ish. How about

std::vector<std::shared_ptr<Foo> > f;
f.push_back(std::make_shared<Foo>(whatever, arguments, you, need));
// ...
f[9]->fooMember();
// ...

No manual cleanup needed :-)

FredOverflow
Except of course that shared_ptr is not yet part of the C++ standard.
anon
@Neil Yes, but I hope every competent programmer is smart enough to google `shared_ptr` and find a solution. If `std::shared_ptr` doesn't work, `std::tr1::shared_ptr` or `boost::shared_ptr` should do the trick :)
FredOverflow