1

I have a class Array which has the following constructor:

explicit Array(int size = 0, const T &v = T()) {
    if (size < 0) {
        throw ArrayExceptions::InvalidLength();
    }
    Array::size = size;
    array = new T[size];
    insertValueIntoArray(size,v);
}

In some other class DataController I have:

Array<Data> dataArray;
int dataAmount;

explicit DataController(int length) : dataArray(length), dataAmount(length) {}

But Data.h does not have a constructor without arguments so the compiler complaints on const T &v = T() of Array.h:

error: no matching function for call to 'Data::Data()'

Instead it has the following constructor:

Data(int length) : length(length), /** Other constructor calls ...  **/ {}

What should I change in order to make the Array use the Data(length) constructor insead of the Data()? I can modify all the files.

I have tried to switch it to:

explicit DataController(int length) : dataArray(length, Data(length)), dataAmount(length) {}

but then I get the same error in line:

array = new T[size];

Minimal example:

template<typename T>
class Array {
    int size;
    T *array;

public:
    explicit Array(int size = 0, const T &value = T()) {
        Array::size = size;
        array = new T[size];
    }

    ~Array() {
        delete[] array;
    }
};

class Data {
private:
    int length;

public:
    Data(int length) : length(length) {}

};

class DataController {
private:
    Array<Data> dataArray;
    int dataAmount;

public:

    explicit DataController(int length) : dataArray(length), dataAmount(length) {}
};

Please suggest solutions without using the std if you can.

8
  • 3
    Please provide a minimal reproducible example Commented Jan 15, 2020 at 11:07
  • Why don't you a signed int instead of an unsigned int? The size parameter would then never be lower than 0. Commented Jan 15, 2020 at 11:11
  • There are different ways to solve this problem. It is impossible to tell what you want without a minimal reproducible example. Commented Jan 15, 2020 at 11:23
  • Does this answer your question? Object array initialization without default constructor Commented Jan 15, 2020 at 11:24
  • I have added a minimal example, please check it if you can Commented Jan 15, 2020 at 11:29

2 Answers 2

1

You have 2 issues in your code.

The first is the default value of v in Array is T() which requires a default constructor. This is easily solved by just not using the default parameter:

dataArray(length, Data(length))

The second more complicated issue is then that:

array = new T[size]

calls the default constructor for each element in array. The simplest solution is to use an existing class that handles this for you like std::vector. If you want to implement it yourself you'll need to allocate memory using malloc, ::operator new or maybe std::aligned_storage then use placement new to initialise each element to a copy of v. You'll need to keep track of both how many elements you've allocated and how many you have initialised then call the destructors only for the initialised elements.

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

5 Comments

This is the only place where I use Array. So what would be the fastest solution? Would it be to make changes in Array? If so, how should I do it?
The fastest, safest and best solution would be to let the standard library do the work for you and use std::vector, you could probably even just replace your Array class with std::vector
unfortunately, I can't use the std library. I thought of changing the arguments of Array and the call of new?
If you can't use the standard library (I don't understand why people trying to teach c++ don't let their students use c++) then you'll need to look here for how to do it manually: stackoverflow.com/questions/4754763/…
@AlanBirtles Actually I don't think it's that a bad idea if students learn about the internals of std::vector and similar. My criticism rather is that they go over to that far too early (and using int instead of size_t is a proof for that this has happened here as well...); that shouldn't be covered at all before using the standard library has got just as natural as using a tooth brush in the morning...
0

Rather than calling new T[size], you can allocate uninitalised memory then copy-construct Ts into it.

template<typename T>
class Array {
    struct aligned_storage {
        struct type {
            alignas(alignof(T)) unsigned char data[sizeof(T)];
        };
    };
    using storage_t = aligned_storage::type;
    int size;
    storage_t * storage;

    void clear() {
        for (int i = 0; i < size; ++i)
            reinterpret_cast<T*>(storage.data[i])->~T();
        delete[] data;
    }

public:
    explicit Array(int size = 0, const T & value = T())
        : size(size), storage(new storage_t[size])
    {
        for (int i = 0; i < size; ++i)
            new (storage.data[i]) T(value);
    }

    Array(const Array & other) 
        : size(other.size), storage(new storage_t[other.size])
    {
        for (int i = 0; i < size; ++i)
            new (data[i]) T(other[i]);
    }

    Array(Array && other) 
        : size(other.size), storage(other.storage)
    {
        other.size = 0;
        other.data = nullptr;
    }

    Array& operator=(Array other) 
    {
        clear();
        storage = other.storage;
        size = other.size;
    }

    ~Array() {
        clear();
    }

    T& operator[](int pos) {
        return *reinterpret_cast<T*>(storage.data[pos]);
    }

    const T& operator[](int pos) const {
        return *reinterpret_cast<T*>(storage.data[pos]);
    }
};

6 Comments

Hmm nice idea. Why do you use free instead of delete? Also, how should the operator= look like?
@vesii because free goes with aligned_alloc. It's undefined behaviour to delete (or delete[]) a void *
I'm actually new to aligned_alloc. Is it similar to malloc? If so, it is possible to switch it to malloc?
@vesii Yes, it does something similar to malloc, but also ensures the result has the specified alignment. This is necessary for over-aligned Ts
I see. So I guess it is not possible to change to malloc? Also I get an error "An attribute list cannot appear here" for alignas(alignof(T)) char[sizeof(T)].
|

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.