Determine array size in constructor initializer

78,941

Solution 1

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.

Solution 2

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!
  }

Solution 3

Use the new operator:

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

Solution 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) { }
};

Solution 5

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 :)

Share:
78,941

Related videos on Youtube

zaratustra
Author by

zaratustra

Updated on February 09, 2021

Comments

  • zaratustra
    zaratustra about 3 years

    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) : ??? { }
    }
    
    • Brian
      Brian about 15 years
      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
      Brian about 15 years
      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.
    • zaratustra
      zaratustra about 15 years
      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.
    • Mooing Duck
      Mooing Duck almost 12 years
      @zaratustra: Why would that make a vector not work? It might need a custom allocator, but I doubt even that.
  • zaratustra
    zaratustra about 15 years
    What would the syntax for using a vector in that situation be like?
  • Brian
    Brian about 15 years
    Don't forget to call delete[] in the constructor if you use this code.
  • Admin
    Admin about 15 years
    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.
  • DevSolar
    DevSolar about 15 years
    vector< int > array; Class( x ) : array( x ) {};
  • Admin
    Admin about 15 years
    better to use the vector for known size too
  • user2584401
    user2584401 about 15 years
    Do you mean "Using a vector will give you automatic leak protection"? :)
  • JaredPar
    JaredPar about 15 years
    @mkb, that's twice today I've made fundamentally stupid comments. Must drink more coffee to wake up before i start posting ;)
  • Martin York
    Martin York about 15 years
    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.
  • Shree
    Shree about 15 years
    accepted, but this was just an option in response to the original question
  • Ricky65
    Ricky65 about 10 years
    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; }
  • AMDG
    AMDG over 9 years
    +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.
  • Tustin2121
    Tustin2121 over 5 years
    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...
  • Spacefish
    Spacefish almost 4 years
    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.
  • Jacob Brunson
    Jacob Brunson about 2 years
    Thank you; I have been searching everywhere for an answer like this. In certain situations this is exactly what is needed