19

I have a class that needs to store an array with a variable size. Ideally, this size would be defined as a parameter given to the constructor of the class.

I can define a constant and then work with that, as seen below:

#include <iostream>
#define ARRSIZE 5

class Classy{
    private:
        int myarray[ARRSIZE];

    public:
        Classy();
        void printarray();
};

Classy::Classy(){
    for(int i = 0; i < ARRSIZE; i++){
        myarray[i] = i * i * 2;
    }
}

void Classy::printarray(){
    for(int i = 0; i < ARRSIZE; i++){
        std::cout << myarray[i] << std::endl;
    }
}

However, I'd like to do it like this:

#include <iostream>
class Classy{
    private:
        int arraysize;
        int myarray[arraysize];

    public:
        Classy(int parraysize);
        void printarray();
};

Classy::Classy(int parraysize){
    arraysize = parraysize;
    for(int i = 0; i < arraysize; i++){
        myarray[i] = i * i * 2;
    }
}

void Classy::printarray(){
    for(int i = 0; i < arraysize; i++){
        std::cout << myarray[i] << std::endl;
    }
}

The compiler really doesn't like my approach though, so I am looking for an alternative way of doing things.

I did some googling on the subject, but my searches did not come up fruitful. I found this approach which does it using dynamic memory allocation. This is something I'd like to avoid, so I am looking for a solution that does not rely on that. It might well be (and I'm starting to think) that it is the only elegant solution to my problem (and if this is the case, the question should of course be closed as duplicate).

Community
  • 1
  • 1
tschoppi
  • 469
  • 2
  • 9
  • 19
  • 7
    Use [`std::vector`](http://en.cppreference.com/w/cpp/container/vector). – Captain Obvlious Oct 04 '14 at 23:13
  • I'm not a huge fan of arrays in general, for most purposes. Unless you really need them for some perceived optimization, `std::vector` is your friend, and more likely to flex with your requirements flexing. But you could use [std::array](http://en.cppreference.com/w/cpp/container/array) ... the convenient C++ alternative to C arrays. – HostileFork says dont trust SE Oct 04 '14 at 23:14
  • 6
    @HostileFork: A `std::array` isn't variable size. `std::unique_ptr` is the Standard component for an array with size set at construction. `std::vector` for an array whose size can vary during its lifetime. – Ben Voigt Oct 04 '14 at 23:15
  • and more generally: you want to learn about `new` (ah, and `delete` of course) for dynamic allocation. – Johannes S. Oct 04 '14 at 23:17
  • @BenVoigt Yes, I'm quite aware. But I got in a discussion about this recently, and [some people rabidly insist they want an array](http://stackoverflow.com/questions/26152367/what-is-the-best-way-to-return-reference-to-a-constant-sized-array-of-pointers). Go figure. Don't shoot the messenger. – HostileFork says dont trust SE Oct 04 '14 at 23:18
  • @HostileFork: I don't see how a discussion about a "constant-sized array" is at all relevant here. – Ben Voigt Oct 04 '14 at 23:19
  • @BenVoigt Then you didn't read the link, or the conversation, as evidenced by the speed of your reply (unless you are an AI). I said what you said. They insist there's a max known capacity. Again, don't shoot the messenger. – HostileFork says dont trust SE Oct 04 '14 at 23:20
  • C++ does not have C99-style flexible-array-members. Use dynamic allocation instead. – Deduplicator Oct 04 '14 at 23:21
  • @HostileFork: I read the title of the other question. Also, in the other question it says "The array has a known size at compile time". That's not true in this case, so the same solution does not apply. – Ben Voigt Oct 04 '14 at 23:22
  • @BenVoigt Well I'm influenced by that recent conversation to mention std::array's existence if one insists on using an array of max capacity and tracking the size independently, and if you sit back with a beer or coffee and read that chat thread...you will see that you're not telling me anything I don't know, and completely preaching to the choir. I am only saying "hey if you choose to allocate a fixed size array, there's this std::array thing you should use instead". Meh. Internet. – HostileFork says dont trust SE Oct 04 '14 at 23:25
  • @JohannesS. You really don't want to learn about `new` until you are much more experienced with C++. Learn the basics first. –  Oct 04 '14 at 23:37

5 Answers5

18

It is required to use dynamic allocation, because sizeof (Classy) must be a compile-time constant. There's no way for your object's internal size to grow. But dynamic allocation doesn't have to be as complicated as that link suggests.

You can do it like this:

#include <memory>
class Classy
{
    private:
        int arraysize;
        std::unique_ptr<int[]> myarray;

    public:
        Classy(int parraysize);
        void printarray();
};

Classy::Classy(int parraysize)
    : arraysize{parraysize}
    , myarray{new int[arraysize]}
{
    for(int i = 0; i < arraysize; i++){
        myarray[i] = i * i * 2;
    }
}

#include <iostream>
void Classy::printarray()
{
    for(int i = 0; i < arraysize; i++){
        std::cout << myarray[i] << std::endl;
    }
}

This will allow the size to vary at the moment of creation, and be fixed thereafter. std::unique_ptr will take care of automatically destroying the array contents when your object is dying.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
6

You want to use templates to solve this problem:

#include <array>

template<std::size_t ArraySize>
class Classy final
{
public:
    static const std::size_t size = ArraySize;

    /* The rest of your public interface here */
private:
    std::array<int, ArraySize> m_array;
};

Then you can use your class like this:

int main()
{
    Classy<5> hasArrayOfFiveElements;
    return 0;
}

You could very well opt to not use std::array, in preference for a c-style array. But we're writing C++, so let's use the better language facilities we have available to us :)

d3coy
  • 395
  • 1
  • 4
4

Well, I think you can't do it without using dynamic memory allocation while using a classic array, but you can use std::vector. You can do it like this:

#include <iostream>
class Classy{
    private:
        int arraysize;
        std::vector<int> myArrayOfInts;

    public:
        Classy(int parraysize);
        void printarray();
};

Classy::Classy(int parraysize){
    arraysize = parraysize;
    for(int i = 0; i < arraysize; i++){
        myArrayOfInts.push_back(i * i * 2);
    }
}

void Classy::printarray(){
    for(int i = 0; i < myArrayOfInts.size(); i++){ //you could also use arraysize, but then you
        std::cout << myArrayOfInts[i] << std::endl;//must update it when you add or remove any
    }                                              // element from vector
}
Mikołaj Mularczyk
  • 959
  • 12
  • 20
3

You need to dynamically allocate your array using new[] and then delete[] it in your destructor. Alternatively, use a std::vector<int> and reserve the amount passed to the constructor. Yet one more method is to make your class templated, taking a size_t argument for the amount of elements you want it to have, but that completely removes the dynamic aspect of it (and you might as well be using std::array at that point.

I know you'd like to avoid dynamic allocation, but it's the most efficient way to do what you want (because vector might take up more space than you expect).

Cave Dweller
  • 502
  • 2
  • 4
  • 17
1

A bit late. However, this may be another approach.

#include <iostream>
#include <cstddef>

class Classy
{
public:
    Classy();
    template <size_t ARRSIZE>
    Classy(int (&arr)[ARRSIZE], size_t size = 0);
    void printarray();
private:
    int* myarray;
    size_t max_size;
    size_t arraysize;
};

template <size_t ARRSIZE>
Classy::Classy(int (&arr)[ARRSIZE], size_t size)
{
    myarray = arr;
    max_size = ARRSIZE;
    arraysize = size;
}

void Classy::printarray(){
    for(int i = 0; i < max_size; i++){
        std::cout << i << " " << myarray[i] << std::endl;
    }
}

int main()
{
    int arr[10];
    Classy c(arr);
    
    c.printarray();

    return 0;
}
bulut
  • 11
  • 2
  • typedef'ing some fixed sized arrays and combining that with this method may be good. – Xofo Jun 21 '22 at 04:26