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

У меня есть класс, скажем 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 ответ

Решение

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

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

  • Необычный способ: использовать 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 (вы сказали, что это просто иллюстративно), и предлагаю более общий ответ.

Другие вопросы по тегам