Создание класса для вызова правильного конструктора при использовании - PullRequest
1 голос
/ 15 января 2020

У меня есть класс Array, который имеет следующий конструктор:

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

В каком-то другом классе DataController У меня есть:

Array<Data> dataArray;
int dataAmount;

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

Но Data.h нет иметь конструктор без аргументов, поэтому компилятор жалуется на const T &v = T() из Array.h:

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

Вместо него есть следующий конструктор:

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

Что я должен изменить, чтобы заставить Array использовать конструктор Data(length) из Data()? Я могу изменить все файлы.

Я пытался переключить его на:

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

, но затем я получаю ту же ошибку в строке:

array = new T[size];

Минимальная пример:

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

Пожалуйста, предлагайте решения без использования std, если можете.

Ответы [ 2 ]

1 голос
/ 15 января 2020

В вашем коде 2 проблемы.

Первое - это значение по умолчанию, v в Array равно T(), для которого требуется конструктор по умолчанию. Это легко решить, просто не используя параметр по умолчанию:

dataArray(length, Data(length))

Вторая более сложная проблема заключается в следующем:

array = new T[size]

вызывает конструктор по умолчанию для каждого элемента в array , Самое простое решение - использовать существующий класс, который обрабатывает это для вас, например std::vector. Если вы хотите реализовать это самостоятельно, вам нужно выделить память с помощью malloc, ::operator new или, возможно, std::aligned_storage, а затем использовать размещение new для инициализации каждого элемента в копию v. Вам нужно будет отследить, сколько элементов вы выделили и сколько вы инициализировали, а затем вызывать деструкторы только для инициализированных элементов.

0 голосов
/ 15 января 2020

Вместо вызова new T[size] вы можете выделить неинициализированную память, а затем скопировать в нее T s.

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]);
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...