views:

3431

answers:

8

Hi, I was wondering if it is possible to declare an array (size not known at this time), as a private member of a class and later set the size in the constructor of the class. For example:

class Test {
int a[];
public:
Test(int size);
};

Test::Test(int size) {
a[size];   // this is wrong, but what can i do here?
}

Is this possible or should I use dynamic arrays? Thanks!

+2  A: 

First of all, it is generally better to initialize things in the initialization list of the constructor, not in the body of the constructor.

You can only initialize an array with a predefined bound if you know that bound at compile time. In this situation, you will need to dynamically allocate the space.

You must remember then to have a destructor that would delete the array when the object is destroyed or you would get a memory leak.

Uri
+14  A: 

Short Answer: No (The size of an array is defined at compile time only)
Long Answer:

You can use a vector to achieve the same result:

class Test
{
    std::vector<int> a;
    public:
        Test(std::size_t size):
            a(size)
        {}
};
Martin York
I wish people would add comments when marking down answers. At least you're back to 0
JaredPar
Haters love to hate anonymously. Hate the haters! I give you a point.
John Dibling
+1 For a good practical answer, if someone has a problem with it explain why (so we can show you Martin is right)
orip
+1 from me to, std::vector<> is great. A minor nitpick would be to use size_t instead of int for the ctor.
Andreas Magnusson
@Andreas Magnusson: Wee spotted. Updated. But if your vector size is overflowing a signed int I think you have other problems.
Martin York
+6  A: 

No this is not possible. Array declarations in headers must have constant sized value. Otherwise it's impossible for constructs like "sizeof" to function properly. You'll need to declare the array as a pointer type and use new[] in the constructor. Example.

class Test { 
    int *a;
public:
    Test(int size) {
       a = new int[size];
    }
    ~Test() { delete [] a; }
private:
    Test(const Test& other);
    Test& operator=(const Test& other);
};
JaredPar
Need to add CopyConstructor and assignment operator and call the correct version od delete. Or use a vector.
Martin York
Drat. I usually call other people out for the same problem ... Will fix shortly
JaredPar
You forgot to correct delete. So I did.
Martin York
Double Wrong ;( It's logical friday
JaredPar
All goes to show why vector is a better idea.
Fred Larson
Definately agree vector is better. The original sample did not use STL so I decided to answer without STL. STL makes C++ so much better. I'm finding it harder and harder to separate the two
JaredPar
You most probably also need a variable which stores the size of a.
ypnos
A: 

No, this is not possible. You should use a dynamic array such as an std::vector. C99 allows a struct to have an unsized array as the last member only, but even when you do this you still have to manually allocate the memory yourself, e.g. with malloc().

Adam Rosenfield
+4  A: 

As other answers have pointed out, the size of an array is fixed at compile time. However, by using templates you can parameterise the size at compile time:

template <int N> class Test {
    int a[N];
public:
    Test() { }
};

Test<5> test;
Test<40> biggertest;

This technique does not let you compute the size at run time (as the dynamic std::vector solution does), but depending on your needs this may be sufficient.

Greg Hewgill
That works, but each version of Test is now a different class. Thus no implicit friendship (thus no accesses for copying etc).
Martin York
Not that you could copy a Test<2> to a Test<1> anyway -- it wouldn't fit. Also, no polymorphism - Test<1> and Test<2> are incompatible types, so every function that handles them has to be templated too.
Steve Jessop
no worries. he can still template the operator= and the cctor.
Johannes Schaub - litb
@Greg: Interesting tip. Yet another reason why Generics != Templates. Or is it Generics < Templates? ;-)
James Schek
A: 

Why not just use a pointer type?

Scott Wisniewski
A: 

What you're talking about is not possible. Classes always have a constant size. You could have your class use a pointer to a dynamically allocated array or you could use a std::vector.

Dave
+2  A: 

See Martin's solution (use std::vector), and remember that even if you need to pass a buffer to a C API std::vector lets you do it by passing &vec[0] :

std::vector<char> vec(10);
memset(&vec[0], 0, vec.size());

It's guaranteed to work, but only if the vector isn't empty (C++ quirks, <sigh>).

orip
Andreas Magnusson
memset was just an example, but you're right :)
orip