26

In the code below I would like array to be defined as an array of size x when the Class constructor is called. How can I do that?

class Class
{
public:
  int array[];
  Class(int x) : ??? { }
}
sbi
  • 219,715
  • 46
  • 258
  • 445
zaratustra
  • 8,148
  • 8
  • 36
  • 42
  • 1
    If you plan to use C++ regularly, I strongly recommend you familiarize yourself with the standard template library. It makes working with collections of data *much* easier. – Brian Apr 15 '09 at 14:38
  • 1
    As an aside, vectors make it relatively easy to work with the array without knowing the size in advance. It isn't necessary to know the size in advance; you can append elements to the end of a vector in (amortized) O(1) time anyhow using push_back. – Brian Apr 15 '09 at 14:43
  • Using vectors brings new problems, since the class I'm trying to vectorize has protected "new" operators. But that wasn't what I asked so nevermind. – zaratustra Apr 16 '09 at 17:12
  • @zaratustra: Why would that make a vector not work? It might need a custom allocator, but I doubt even that. – Mooing Duck Jul 06 '12 at 00:21

11 Answers11

73

You folks have so overcomplicated this. Of course you can do this in C++. It is fine for him to use a normal array for efficiency. A vector only makes sense if he doesn't know the final size of the array ahead of time, i.e., it needs to grow over time.

If you can know the array size one level higher in the chain, a templated class is the easiest, because there's no dynamic allocation and no chance of memory leaks:

template < int ARRAY_LEN > // you can even set to a default value here of C++'11

class MyClass
  {   
  int array[ARRAY_LEN]; // Don't need to alloc or dealloc in structure!  Works like you imagine!   
  }

// Then you set the length of each object where you declare the object, e.g.

MyClass<1024> instance; // But only works for constant values, i.e. known to compiler

If you can't know the length at the place you declare the object, or if you want to reuse the same object with different lengths, or you must accept an unknown length, then you need to allocate it in your constructor and free it in your destructor... (and in theory always check to make sure it worked...)

class MyClass
  {
  int *array;

  MyClass(int len) { array = calloc(sizeof(int), len); assert(array); }   
  ~MyClass() { free(array); array = NULL; } // DON'T FORGET TO FREE UP SPACE!
  }
Jeff Diamond
  • 749
  • 1
  • 5
  • 3
  • 1
    This is a bad use of templates. I followed your suggestion and added an Array length template to my class, but now my Linker is yelling at me. Templated classes need to be either entirely inlined in the header, or I have to make new template versions of each method signature in the class for every array length I ever use. I want to -1 this answer now, but apparently my vote is locked in now... – Tustin2121 Jan 31 '19 at 19:24
  • 1
    This is a possible way but it makes it hard to use together with dynamic cast and prevents using a source file unless every case is instantiated explicitely. If a vector is desired without the use dynamic memory allocation, a custom allocator or using a library like the embedded template library might help. – Spacefish May 28 '20 at 14:26
  • Thank you; I have been searching everywhere for an answer like this. In certain situations this is exactly what is needed – Jacob Brunson Mar 01 '22 at 02:33
28

You can't initialize the size of an array with a non-const dimension that can't be calculated at compile time (at least not in current C++ standard, AFAIK).

I recommend using std::vector<int> instead of array. It provides array like syntax for most of the operations.

jedwards
  • 29,432
  • 3
  • 65
  • 92
Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
16

Use the new operator:

class Class
{
   int* array;
   Class(int x) : array(new int[x]) {};
};
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • 6
    Don't forget to call delete[] in the constructor if you use this code. – Brian Apr 15 '09 at 14:14
  • 8
    If you do this you will also need a copy constructor , an assignment operator and a destructor. Useing a std::vector gives you exactly the same functionality but requires none of these. –  Apr 15 '09 at 14:15
  • +1 This actually answers the OP's question by initializing the size of an array, though it actually is replacing `int *array` which isn't an array, with the list in the constructor. @(anon) besides a copy constructor, an assignment operator, and a destructor, this truly answers the question. – AMDG Oct 25 '14 at 11:41
4

Don't you understand there is not need to use vector, if one wants to use arrays it's a matter of efficiency, e.g. less space, no copy time (in such case if handled properly there is not even need to delete the array within a destructor), etc. wichever reasons one has.

the correct answer is: (quoted)

class Class
{
   int* array;
   Class(int x) : array(new int[x]) {};
};

Do not try to force one to use non optimal alternatives or you'll be confusing unexperienced programmers

4

I had the same problem and I solved it this way

class example
{
  int *array;

  example (int size)
  {
    array = new int[size];
  }
}
4

I don't think it can be done. At least not the way you want. You can't create a statically sized array (array[]) when the size comes from dynamic information (x).

You'll need to either store a pointer-to-int, and the size, and overload the copy constructor, assignment operator, and destructor to handle it, or use std::vector.

class Class
{
  ::std::vector<int> array;
  Class(int x) : array(x) { }
};
AFoglia
  • 7,968
  • 3
  • 35
  • 51
3

Sorry for necroing this old thread. There is actually a way to find out the size of the array compile-time. It goes something like this:

#include <cstdlib>

template<typename T>
    class Class
    {
        T* _Buffer;

        public:
        template<size_t SIZE>
            Class(T (&static_array)[SIZE])
            {
                _Buffer = (T*)malloc(sizeof(T) * SIZE);

                memcpy(_Buffer, static_array, sizeof(T) * SIZE);
            }

            ~Class()
            {
                if(_Buffer)
                {
                    free(_Buffer);
                    _Buffer = NULL;
                }
            }
    };

int main()
{
    int int_array[32];
    Class<int> c = Class<int>(int_array);

    return 0;
}

Alternatively, if you hate to malloc / new, then you can create a size templated class instead. Though, I wouldn't really recommend it and the syntax is quite ugly.

#include <cstdio>

template<typename T, size_t SIZE>
    class Class
    {
        private:
            T _Array[sz];
        public:
            Class(T (&static_array)[SIZE])
            {
                memcpy(_Array, static_array, sizeof(T) * SIZE);
            }
    };

int main()
{
    char int_array[32];
    Class<char, sizeof(int_array)> c = Class<char, sizeof(int_array)>(int_array);
    return 0;
}

Anyways, I hope this was helpful :)

user563910
  • 161
  • 2
  • 2
  • In C++11 a superior method of determining the size of a built-in array is using a constexpr template function. For example: template < class T, std::size_t N > constexpr std::size_t size( const T (&array)[N] ) { return N; } – Ricky65 Feb 19 '14 at 14:23
1

Like already suggested, vector is a good choice for most cases.

Alternatively, if dynamic memory allocation is to be avoided and the maximum size is known at compile time, a custom allocator can be used together with std::vector or a library like the embedded template library can be used.

See here: https://www.etlcpp.com/home.html

Example class:


#include <etl/vector.h>

class TestDummyClass {
public:
    TestDummyClass(size_t vectorSize) {
        if(vectorSize < MAX_SIZE) {
            testVector.resize(vectorSize);
        }
    }

private:
    static constexpr uint8_t MAX_SIZE = 20;
    etl::vector<int, MAX_SIZE> testVector;
    uint8_t dummyMember = 0;
};
Spacefish
  • 305
  • 4
  • 11
1

Instead of using a raw array, why not use a vector instead.

class SomeType {
  vector<int> v;
  SomeType(size_t x): v(x) {}
};

Using a vector will give you automatic leak protection in the face of an exception and many other benefits over a raw array.

Brian
  • 25,523
  • 18
  • 82
  • 173
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • Do you mean "Using *a vector* will give you automatic leak protection"? :) – Matt K Apr 15 '09 at 14:24
  • @mkb, that's twice today I've made fundamentally stupid comments. Must drink more coffee to wake up before i start posting ;) – JaredPar Apr 15 '09 at 14:28
0

You can't do it in C++ - use a std::vector instead:

#include <vector>

struct A {
   std::vector <int> vec; 
   A( int size ) : vec( size ) {
   }
};
jwfearn
  • 28,781
  • 28
  • 95
  • 122
0

Declare your array as a pointer. You can initialize it in the initializer list later through through new.

Better to use vector for unknown size.

You might want to look at this question as well on variable length arrays.

Community
  • 1
  • 1
Shree
  • 4,627
  • 6
  • 37
  • 49
  • better to use the vector for known size too –  Apr 15 '09 at 14:17
  • BAD idea. Doing the memory management on a pointer that acts like an array is not trivial in the presence of exceptions. Use std::vector or std::tr1::array. – Martin York Apr 15 '09 at 15:51
  • accepted, but this was just an option in response to the original question – Shree Apr 15 '09 at 16:11