Как я могу сделать класс со ссылочным членом данных конструктивным без аргументов? - PullRequest
0 голосов
/ 27 октября 2018

У меня есть класс, скажем C, где один из данных члена, скажем, X, зависит от ввода пользователя.Пользовательский ввод может отличаться при каждом запуске, и в моем текущем проекте все экземпляры моих классов хранят ссылку на один и тот же объект X.

Как я могу настроить дизайн так, чтобы он позволял конструктору по умолчанию без аргументов?

Таким образом, я могу использовать конструктор копирования / назначения, создавать массивы C, использовать временное значение и т. Д.

Ниже приведен минимальный рабочий пример, иллюстрирующий мой вопрос.В случае, с которым я работаю, тег относится к некоторым внешним ресурсам.

#include <iostream>
#include <string>
#include <vector>
#include <cassert>

using namespace std;

struct Tag {
    int N;
    string tag;
};

template<typename T>
struct Vec {
    const Tag& tag;
    T* vec;

    Vec(const Tag& tag_) : tag(tag_) {
        vec = new T[tag.N];
    }

    ~Vec() {
        delete [] vec;
    }
};

Tag make_tag(vector<string>& args) {
    assert(args.size() == 3);
    int N = stoi(args[1]);
    return Tag {N, args[2]};
}

vector<string> arguments(int argc, char* argv[]) {
    vector<string> res;
    for(int i = 0; i < argc; i++)
        res.push_back(argv[i]);
    return res; 
}

int main(int argc, char* argv[]) {
    vector<string> args = arguments(argc, argv);
    Tag tag0 = make_tag(args);
    Tag tag1;
    Vec<double> vec(tag0);
    return 0;
}

1 Ответ

0 голосов
/ 27 октября 2018

Как настроить дизайн так, чтобы он позволял использовать конструктор по умолчанию без аргументов?

Итак, я бы предложил три варианта:

  • Необычный способ : Используйте член std::optional<std::reference_wrapper<T>>.std::reference_wrapper предназначен для размещения ссылки там, где вы не уверены, что ссылка будет работать как есть.std::optional<T> содержит либо T, либо nullopt (т.е. без значения).Преимуществом инициализатора по умолчанию для optional является отсутствие аргументов, поэтому вы можете использовать конструктор по умолчанию для случая без аргументов C.

  • Старая школа : используйте простой элемент указателя вместо ссылки.Инициализируйте его на nullptr в конструкции без аргументов.(@RemyLebeau также предложил это в комментарии.)

  • Умный способ RAII : замените ваш класс C на std::optional<C>.Это означает, что конструкция без аргументов фактически не создает C - она ​​просто сохраняет nullopt, задерживая фактическую конструкцию на потом.Это решение актуально, когда вы должны поддерживать инвариант C, хранящий ресурсы на протяжении всего его существования;он также имеет преимущество, оставляя в качестве ссылочного элемента C как const.

Я намеренно не рассматриваю ваш MWE (вы сказали, что это просто иллюстративно),и я предлагаю более общий ответ.

...