Как я могу инициализировать атрибут, не зная, какие конструкторы у него есть? - PullRequest
0 голосов
/ 06 января 2020

Мне нужно реализовать следующий класс:

template <class Element, class Compare = std::equal_to<Element>>
class UniqueArray {
    Element* data;
    unsigned int size;
    unsigned int max_size;
public:
    explicit UniqueArray(unsigned int size);
    UniqueArray(const UniqueArray& other);
    ~UniqueArray();
    UniqueArray& operator=(const UniqueArray&) = delete;
    unsigned int insert(const Element& element);
    bool getIndex(const Element& element, unsigned int& index) const;
    const Element* operator[] (const Element& element) const;
    bool remove(const Element& element);
    unsigned int getCount() const;
    unsigned int getSize() const;
};

Проблема в том, что я не могу предположить, что Element имеет конструктор defualt. Предполагая, что я не вижу реализации класса Element, это означает, что могут быть другие конструкторы, но я не знаю, сколько существует параметров и каковы их типы. Как я могу инициализировать атрибут данных UniqueArray?

Например, Элемент может быть точкой, которая имеет конструктор с двумя аргументами (и не имеет конструктора по умолчанию), но суть в том, что я не знаю, какой элемент отправляется, и я не знаю, какой конструктор имеет этот элемент. Код должен быть обобщенным c.

Ответы [ 3 ]

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

Во-первых, требования к сбору:

  • "std:equal_to - это единственное, что я могу использовать из стандартной библиотеки"
  • Есть член max_size и size , getCount() возвращает текущий размер и getSize() максимальный размер (примечание: это ужасно ...)

Так что я бы предположил, что конструктор вашему классу следует выделить достаточно памяти для хранения size (параметр) объектов класса Element.

Правильный способ сделать это будет, как это предлагается в Rustyx 'ответ - использовать std::aligned_storage. Так как это для домашней работы в университете, и ваш лектор / профессор / человек, который написал это задание, вероятно, не знает достаточно о C ++, чтобы заботиться / понимать проблемы, которые вам, вероятно, лучше всего подходят с чем-то вроде этого:

// in constructor, I repeat, THIS IS HORRIBLE!
max_size = size; // better use member initialization, though
data = reinterpret_cast<Element*>(new unsigned char[sizeof(Element) * max_size]);

При вставке вы используете размещение нового для создания нового элемента в качестве копии:

new (data[index_for_new_element]) Element(element);

Для удаления вам нужно вызвать деструктор вручную!

data[index_to_erase].~Element();

Я повторяю: Это не то, как вы написали бы такой код в реальном приложении! Это не научит вас чему-то ценному!

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

Непонятно, что должен делать конструктор UniqueArray(unsigned int size) - построить по умолчанию столько элементов или зарезервировать хранилище?

Если только резервирует хранилище, то вы можете использовать std::aligned_storage, чтобы отделить выделение памяти от конструкции объекта и позволить пользователю UniqueArray создать элементы:

template <class Element, class Compare = std::equal_to<Element>>
class UniqueArray {
    using storage_type = typename std::aligned_storage<sizeof(Element), alignof(Element)>::type;
    storage_type* data;
    unsigned int size;
    unsigned int max_size;
public:
    explicit UniqueArray(unsigned int size) : size(0), max_size(size) {
        data = new storage_type[size];
    }
    ~UniqueArray() {
        for (unsigned pos = 0; pos < size; ++pos) {
            // note: needs std::launder as of C++17
            reinterpret_cast<Element*>(&data[pos])->~Element();
        }
        delete[] data;
    }
    Element& operator[](unsigned pos) {
        // note: needs std::launder as of C++17
        return *reinterpret_cast<Element*>(&data[pos]);
    }
    void insert(const Element& element) {
        new (&(*this)[size++]) Element(element); // placement-new
    }
    // ...
};

struct A {
    int a, b;
    A(int x) : a(x), b(x + 5) {}
};
int main() {
    UniqueArray<A> arr(3);
    arr.insert({ 2 });
    std::cout << arr[0].b << std::endl; // prints "7"
}
0 голосов
/ 06 января 2020

После обсуждения с преподавателем это способ go об этом:

data переменная-член будет инициализирована в массив нулевых указателей. каждый указатель указывает на элемент.

Можно предположить, что существует конструктор копирования. Всякий раз, когда мы хотим вставить новый элемент в массив, мы вызываем insert(), и эта функция вставляет копию полученного элемента в качестве аргумента.

...