1

Let's say I have an object called Square with the constructor Square(int rx, int ry), i want to create a dynamic array of Squares, with different arguments in the constructor:

Square *squares = new Square[10];  
for (int i = 0; i < 10; i++)
{
     squares[i] = new Square(i, i);
}

However this fails, saying no appropriate default constructor available. So how do i create an empty or NULL array and then do constructions later?

EDIT: This has to be an array, due to other things in code, to hard to explain here.

1
  • You can create a std::vector and then use its underlying array ( herbsutter.com/2008/04/07/… ). You then get to avoid worrying about memory leaks. Commented Mar 30, 2011 at 20:48

9 Answers 9

7

Use vector. It doesn't have this problem as long as Square is copyable.

vector<Square> squares;
for (int i = 0; i < 10; i++)
{
     squares.push_back(Square(i, i));
}
Sign up to request clarification or add additional context in comments.

Comments

5

You could make an array of pointers to Square:

Square **squares = new Square*[10];

for (int i = 0; i < 10; i++)
{
     squares[i] = new Square(i, i);
}

As others have pointed out, it is a good idea to consider using std::vector instead.

4 Comments

I didn't say it was pretty. ;)
In fact, the original poster talks about creating NULL array so array of pointers seems to be the best way.
This has the drawback that you need to delete each element separately in addition, and have 10 separate allocations. You will therefor not have one continuous buffer for your square objects. That may be important and a good idea to mention.
@ecik - An array of pointers is never the right way. :-) An empty std::vector would do.
1

The way the standard library containers do it is with placement new. Just using a standard library container, like std::vector, is definitely the easiest way. And placement new is the hardest. Allocating individual objects and keeping pointers in the array, like Xeo mentioned, falls in the middle.

Comments

1

You should make an array of pointers to SQuare.

However, I would also recommend to use a std::vector instead of a "classic" array, this is a good solution if Square is copyable.

However, if it is not, or if you still decide to go the pointer way, make it a std::vector of shared_ptr to leave all the deletion burden to the compiler.

This would give something like:

#include <vector>
#include <boost/shared_ptr.hpp> //on some compilers, you can use #include <memory> instead

using std::vector;
using boost::shared_ptr; // or using std::shared_ptr

vector<shared_ptr<Square> > squares(10);

for (int i = 0; i < 10; i++)
{
     squares[i].reset(new Square(i, i));
}

To go even further, you could take a look at the Boost Pointer Container library.

Comments

1

Use vector in programs where applicable. If you really need to use a raw new, you can use placement new.

Square *squares = static_cast<Square*>(operator new(sizeof(*squares) * 10));
for (int i = 0; i < 10; i++) {
  new (static_cast<void*>(squares + i)) Square(i, i);
}

And delete it with operator delete(squares);. Notice that you need to manually call the destructors of these objects then. Alternatively, you can create the objects with a raw storage iterator

std::raw_storage_iterator<Square*, Square> rsi(squares);
for (int i = 0; i < 10; i++) {
  *rsi++ = Square(i, i);
}

The need to manually call the destructors at the end of use stays, of course.

Comments

1

I would recommend you use a std::vector instead of a dynamically-allocated array. std::vectors are much easier to work with, and don't leak memory.

However, the missing constructor the error message refers to is Square's constructor. You need to add a constructor for Square that takes no arguments. ONE of the following will do:

class Square {
    Square() { ... }
    // Square with dimensions of 0 is empty
    Square(int length=0, int width=0) { ... }
    ...
};

Please note that if you put both of these in the file, then you will get an error, because it will be impossible to know which constructor to call when no arguments are given.

You'll probably want the default constructor even if you use a std::vector. "Probably," because you can get around it, if you limit yourself to std::vector's constructors that take an object, eg.:

std::vector<Square> foo(10, Square(0, 0));
// reassign each element accordingly

I've already added this as a comment to the question itself. As Herb Sutter says, std::vector is designed to be interchangeable with arrays:

Why is it so important that vectors be contiguous? Because that’s what you need to guarantee that a vector is layout-compatible with a C array, and therefore we have no reason not to use vector as a superior and type-safe alternative to arrays even when we need to exchange data with C code. So vector is our gateway to other languages and most operating systems features, whose lingua franca is the venerable C array.

The syntax, by the way is (assuming v is a vector) &v[0]. That is, take the address of the first element (and it's a reference, so that works on all std::vectors except for std::vector<bool>) and you'll get a pointer that you can pass to any function that expects a pointer (you can, of course, get the length of the "array" as v.size()).

Comments

0

Simple use a pointer to a pointer

Square **squares = new Square*[10];  

And it should work. But I guess you are really better off when you start using STL containers like vector

Comments

0

Use std::vector, or use the same technique it does: allocate "raw" storage space with the global new operator, and create objects in that storage using placement new (and destroy them by invoking the dtor directly instead of using delete.

Comments

0
Square *squares = new Square[10];

This operation calls the default constructor 10 times. And there is not one in your snippet resulting error. So, provide one. Just write setter method to initialize class members.

for (int i = 0; i < 10; i++)
{
     squares[i] = new Square(i, i);
}

By new operation again in the for loop, you are just leaking the memory acquired before but does what you think.

Also don't forget to call delete[] on squares.

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.