16

I want to create an array that holds pointers to many object, but I don't know in advance the number of objects I'll hold, which means that I need to dynamically allocate memory for the array. I have thought of the next code:

ants = new *Ant[num_ants];
for (i=1;i<num_ants+1;i++)
{
    ants[i-1] = new Ant();
}

where ants is defined as Ant **ants; and Ant is a class.

Will it work?

6
  • @Carl Norum;I can't try it at the moment, as I'm only starting to write the code, and I still have many parts missing. Commented May 4, 2011 at 17:48
  • 2
    You might want to change your loop to iterate from 0 to num_ants, and assign to ants[i]. No need to offset everything by 1. Commented May 4, 2011 at 17:50
  • 2
    There's no reason you couldn't try it with a dummy empty class. Just create a class Foo that has nothing in it, and use the same logic. Commented May 4, 2011 at 17:51
  • 1
    Are you sure that the above code works? When I write the following in Visual Studio, I get a compiler error: Ant** ants = new *Ant[5]; Commented Apr 2, 2016 at 22:22
  • 3
    Syntax error: '*'. Shouldn't it be Ant** ants = new Ant*[numants];? I'm not a C++ expert, but I think this is a typo. Commented Apr 3, 2016 at 19:43

5 Answers 5

30

Will it work?

Yes.

However, if possible, you should use a vector:

#include <vector>

std::vector<Ant*> ants;
for (int i = 0; i < num_ants; ++i) {
    ants.push_back(new Ant());
}

If you have to use a dynamically allocated array then I would prefer this syntax:

typedef Ant* AntPtr;
AntPtr * ants = new AntPtr[num_ants];
for (int i = 0; i < num_ants; ++i) {
    ants[i] = new Ant();
}

But forget all that. The code still isn't any good since it requires manual memory management. To fix that you could to change your code to:

std::vector<std::unique_ptr<Ant>> ants;
for (auto i = 0; i != num_ants; ++i) {
    ants.push_back(std::make_unique<Ant>());
}

And best of all would be simply this:

std::vector<Ant> ants(num_ants);
Sign up to request clarification or add additional context in comments.

6 Comments

Can you really assign the result of new to an array?
@Mark B: Good catch. Fixed it.
So basically new Ant* [num_ants] is a fake call, as it doesn't call constructor at all right? Only allocates the pointer array. Thats why the new seems as if it is called twice.
Why "should" an std::vector be used?
It is worth noting that if Ant class is base class for other classes and instances of this derived classes also can be stored in array of Ants then the latter method (std::vector<Ant>) does not fit.
|
4
std::vector<Ant> ants(num_ants);
ants.resize(new_num_ants);

4 Comments

If the OP wants to use pointers to Ants, the declaration would be: std::vector<Ant *> ant_pointers(num_ants);
You would also have to use std::generate to new all the respective items.
I down voted because the OP directly mentioned he wanted to use pointers, which as @ThomasMatthews mentioned, needs a different declaration. Your answer is good for a different case though.
I upvoted because OP apparently doesn't know of the array-of-objects being a better option
3

Yes that's the general idea. However, there are alternatives. Are you sure you need an array of pointers? An array of objects of class Ant may be sufficient. The you would only need to allocate the array:

Ant *ants = new Ant[num_ants];

In general, you should prefer using std::vector to using an array. A vector can grow as needed, and it will handle the memory management for you.

In the code you have posted, you would have to delete each element of ants in a loop, and then delete the array itself, delete [] ant. Keep in mind the difference between delete and delete [].

One more point, since array indices in C++ are 0-based, the following convention is used to iterate over the elements:

for (i=0; i<num_ants; i++)
{
    ants[i] = new Ant();
}

This makes code much more readable.

Comments

3

Do you really need to hold pointers to the items? If you can use objects by value, a far simpler approach is to use a vector: std::vector<Ant> ants(num_ants);. Then not only do you not have to write looping, but you don't have to worry about memory leaks from raw pointers and other object management items.

If you need object pointers to say satisfy an API you can still use vector for the outer container and allocate the objects manually.

struct CreateAnt
{
    Ant* operator()() const { return new Ant; }
};

std::vector<Ant*> ants(num_ants);  // Create vector with null pointers.
std::generate(ants.begin(), ants.end(), CreateAnt());

Comments

2
std::vector<Ant*> ants( num_ants );
for ( int i = 0; i != num_ants; ++ i ) {
    ants[i] = new Ant;
}

Or if you don't know how many in advance:

std::vector<Ant*> ants;
while ( moreAntsNeeded() ) {
    ants.push_back( new Ant );
}

On the other hand, I think you need to ask yourself whether Ant is an entity type or a value. If it's a value, you'll probably want to skip the pointers and the dynamic allocation; if it's an entity type, you'll have to consider the lifetime of the object, and when and where it will be deleted.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.