1

I want to make a dynamic array of foo, with the number of items being x. Arguments y and z are to be passed to the constructor of the item foo. I was hoping to do something similar to:

Foo* bar = new Foo(y, z)[x];

However that produced the following compiler error:

 error: expected `;' before '[' token

So after speaking with an experienced friend, he gave me this, which he admitted was a lazy way of doing it, but it works. I was wondering, is there a better/proper way?

Foo* bar = (Foo*) new int[x];
for (int i = 0; i < x; i++) {
    bar[i] = Foo(y, z);
}
1
  • 6
    You and your friend should get a good book to get a good base of understanding. I mean that second code block is just wrong, why allocate int and then cast to foo? That's almost certainly undefined behavior. Commented Sep 2, 2010 at 17:25

4 Answers 4

11

"I want to make a dynamic array" So use a std::vector, it exists for a reason.

std::vector<foo> bar(x, foo(y, z));

This creates a dynamic array with x elements initialized to foo(y, z).


The above makes copies of the second parameter, x times. If you want to generate values for the vector, use generate_n:

std::vector<double> weights;
std::generate_n(std::back_inserter(weights), x, ...);

You replace ... with a function or functor to call, that returns a value. Generally you make a functor:

struct generate_weight
{
    double operator()() const
    {
        return random(1e-3);
    }
};

Giving:

std::generate_n(std::back_inserter(weights), x, generate_weight());

If your compiler supports C++0x, you can take advantage of lambda's. These do the same thing, except they keep the code concise and localized:

std::generate_n(std::back_inserter(weights), x,
                [](){ return random(1e-3); } );
Sign up to request clarification or add additional context in comments.

4 Comments

Whilst this works fine, in this example it returns the same number for all items in the array: std::vector<double> weights(x, random(1e-3));
@Daniel: Indeed it does, it initializes it to x copies of foo(y, z). Your question said nothing about anything else; ask real questions to get real answers. I've updated my answer.
I was just looking to see if that was the expected behavior, having no experience with STL before this. I used the random(1e-3) as an example. Thanks for the extended answer.
@Daniel: No problem. Programming C++ without using the standard library is...unwise.
1

If you want to initialize each element to the same value, then do as GMan suggested above:

std::vector<foo> bar(x, foo(y, z));

You will have a vector of X elements, each with the same foo(y,z);

If you want a unique value for each of the foos you will need to initialize it in a loop. one simple example of how is:

std::vector<foo> bar;

    for (int i = 0; i < x; ++i)
    {
        // initialize X foos with different values for each foo.
        bar.push_back(foo(i, random(i)));
    }

Comments

1

Firstly, the only initializer you can use in the array new-expressions is (). So, these are you only options if you want to use new-expression

foo *bar = new foo[x];   // 1. no initializer
foo *bar = new foo[x](); // 2. `()` initializer

Depending on how foo is defined, these two might behave identically or differently.

Secondly, since you can't pass the constructor arguments (y,z) in new-expression, you have to default-construct your array (as shown above) and then use assignment to give your array elements specific values. For this your foo has to be default-constructible and copy-assignable. The code will look pretty much like what your "experienced friend" suggested, but with proper types (instead of int). What you have now is useless (where did that int come from?). Most likely you misunderstood your experienced friend. This is how it is supposed to look

foo *bar = new foo[x];
for (int i = 0; i < x; i++)
  bar[i] = foo(y,z);

Thirdly, in your specific case std::vector will do the same thing in a much more elegant way.

1 Comment

That was my original code, however I would have to make a constructor to handle no arguments (as you said, 'default constructible'?) when using "foo *bar = new foo[x];". And then re-init them all as you have done.
0

If you insist in not using std at least do it properly. This is not safe and has BIG alignment issues.

size_t x = 10;
foo * bar= static_cast<foo*> (::operator new ( sizeof(foo)* x));
for (size_t i=0; i<x; ++i)
{
    new (&bar[i]) foo (1,1); 
}

::operator delete (bar); 

3 Comments

There's no alignment issues here, operator new returns a maximally aligned block of memory.
@GMan - I'm afraid not this will ignore alignment of foo.
Again, there are no alignment issues. §3.7.3.1/2: "...The pointer returned shall be suitably aligned so that it can be converted to a pointer of any complete object type and then used to access the object or array in the storage allocated..."

Your Answer

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