20

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

11
  • 7
    Use std::vector. Commented Oct 4, 2014 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 ... the convenient C++ alternative to C arrays. Commented Oct 4, 2014 at 23:14
  • 6
    @HostileFork: A std::array isn't variable size. std::unique_ptr<T[]> is the Standard component for an array with size set at construction. std::vector<T> for an array whose size can vary during its lifetime. Commented Oct 4, 2014 at 23:15
  • and more generally: you want to learn about new (ah, and delete of course) for dynamic allocation. Commented Oct 4, 2014 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. Go figure. Don't shoot the messenger. Commented Oct 4, 2014 at 23:18

5 Answers 5

19

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.

Sign up to request clarification or add additional context in comments.

Comments

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

1 Comment

This doesn't let you "pass the size to the constructor" as the question requires.
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
}

4 Comments

std::vector needs a type
yes, of course, I've forgot writing it :D thanks, I've updated it.
Why do you track the size of the std::vector with int arraysize;? Can't you just use the vector's size() method?
you can. I have tried to edit the op's code as little as I could. But it would be better to do it with size method.
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).

Comments

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

1 Comment

typedef'ing some fixed sized arrays and combining that with this method may be good.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.