Идиома для инициализации класса С++ до нуля

Рассмотрим следующий класс C++:

struct Point
{
    int x;
    int y;

    explicit Point() =default; // 1
    explicit Point(int x_, int y_): x(x_), y(y_) { } // 2
};

Второй конструктор полезен для создания Point с определенными значениями x и y. Первый существует, так что я могу по умолчанию построить Point. Однако для эффективности он имеет значение defaulted и не устанавливает x и y равными нулю. Если бы я действительно хотел установить все элементы равными нулю, я мог бы иметь другой конструктор:

explicit Point(int val) : x(val), y(val) { } // 3

Таким образом, я могу либо инициализировать Point по умолчанию, либо инициализировать его, установив для всех элементов нулевое значение:

Point p1;    // Don't initialize members.
Point p2(0); // Initialize all members to zero.

Проблема с третьим конструктором заключается в том, что я действительно могу передать любое значение, а не только ноль. Например:

Point p(1); // Both x and y set to 1! Is this the intent? If so,
            // probably should have used Point p(1, 1) instead.

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

explicit Point(Default) : x(0), y(0) { } // 4

Где Default можно определить просто как:

struct Default { };

Затем я могу контролировать, когда я хочу, чтобы Point был инициализирован значениями по умолчанию:

Point p1;            // Don't initialize members.
Point p2(Default()); // Initialize members with default values.

Какой метод будет считаться лучше: метод с контрольным типом Default (№ 4) или конструктор, который принимает одно значение и инициализирует все элементы этим значением (№ 3)? Каковы плюсы/минусы двух методов? Или есть другой лучший механизм для этого?

Изменить: обратите внимание, что этот простой класс был выбран для иллюстрации; на самом деле может быть гораздо больше членов, которым нужны определенные значения по умолчанию, чтобы считаться "инициализированными".


person Francis Xavier    schedule 04.12.2016    source источник
comment
Обратите внимание, что вы также можете использовать инициализацию значения. Point p{};.   -  person juanchopanza    schedule 04.12.2016


Ответы (3)


Сделайте свою жизнь проще, создавайте простые структуры данных, такие как агрегаты:

struct Point
{
    int x;
    int y;
};

Теперь вы можете использовать агрегатную инициализацию:

Point p;      // members uninitialized
Point p{};    // members set to 0
Point p{1,2}; // members set to 1,2
person Baum mit Augen    schedule 04.12.2016

Наиболее распространенной практикой, которую я вижу для этого, является реализация конструктора без аргументов со списком инициализации, который содержит каждый член класса, установленный на любое значение по умолчанию, которое вы хотите.

Point(): x(0), y(0) { }

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

person Erix    schedule 04.12.2016
comment
Я думаю, что это подход, принятый для std::complex. - person Chris Drew; 04.12.2016

Другой вариант — использовать:

struct Point
{
    int x;
    int y;

    explicit Point(int x_ = 0, int y_ = 0): x(x_), y(y_) {}
};

Point p1;        // 0, 0
Point p2(1);     // 1, 0
Point p3(1, 10); // 1, 10
person R Sahu    schedule 04.12.2016