Какой конструктор / оператор копирования / перемещения определите для простых структур?

Моя программа использует простую структуру Rect который определяется как

struct Rect {
    int x1, y1, x2, y2;

    Rect()
    : x1(0), y1(0), x2(0), y2(0) { }

    Rect(int x1, int y1, int x2, int y2)
    : x1(x1), y1(y1), x2(x2), y2(y2) { }
};

Должен ли я определить конструктор копирования / перемещения или оператор присваивания, или я могу рассчитывать на компилятор для их автоматической генерации? Вопрос в контексте скорости и причин использования (например, конструктор перемещения может влиять на скорость выполнения программы).

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

    Rect(const Rect& r)
    : x1(r.x1), y1(r.y1), x2(r.x2), y2(r.y2) { }

    Rect(Rect&& r)
    : x1(r.x1), y1(r.y1), x2(r.x2), y2(r.y2) { }

    Rect& operator = (const Rect& r) {
        x1 = r.x1;
        y1 = r.y1;
        x2 = r.x2;
        y2 = r.y2;
    }

4 ответа

Решение

Q1: Можете ли вы рассчитывать на компилятор для их автоматической генерации?

Да (в вашем примере). См. Стандарт C++11 (пункт 12) или статью " Неявное движение не пойдет"! (хорошая диаграмма в конце). Подводя итог (и упростить), все следующие специальные функции-члены будут автоматически сгенерированы (неявно объявлены и определены как значения по умолчанию):

  • Разрушитель - потому что ты не объявил это.
  • Копировать конструктор - потому что вы не объявили об этом ни одного из MC и MAO.
  • Оператор назначения копирования - потому что вы не объявили об этом ни одного из MC и MAO.
  • Move Constructor - потому что вы не объявили об этом ни одного из D, CC, CAO и MAO.
  • Оператор назначения перемещения - потому что вы не объявили об этом, ни D, CC, CAO и MC.

(Я использовал уродливые инициалы только для того, чтобы элементы списка оставались по одной в каждой строке.) В дополнение к вышеприведенному "потому что", для всех, кроме деструктора, есть дополнительное ограничение, что сгенерированные значения по умолчанию должны иметь смысл, т.е. все члены данных должны быть копируемый (для CC и CAO) или подвижный (для MC и MAO). (На самом деле точные правила немного сложнее, но я не хочу перефразировать Стандарт здесь.)

В2: Верны ли автоматически сгенерированные функции?

Да (в вашем примере). Все ваши данные участников (здесь просто ints) иметь правильную семантику копирования / перемещения (их конструкторы копирования / перемещения и операторы присваивания работают правильно, а те, которые автоматически генерируются для Rect позвоню им).

Q3: Во всяком случае, вы должны определить их вручную?

Я не вижу в этом преимущества (в вашем примере) и потенциальных проблем (как в вашем примере, см. Комментарии).

Если вы хотите быть многословным по некоторым причинам, вы можете объявить их по умолчанию самодокументированными, например:

struct Rect {
    int x1, y1, x2, y2;

    Rect () : Rect( 0, 0, 0, 0 ) { }

    Rect ( int x1, int y1, int x2, int y2 )
    : x1(x1), y1(y1), x2(x2), y2(y2) { }

    // Rect is Copy/Move Constructible and Assignable
    Rect( Rect const & ) = default;
    Rect( Rect && ) = default;
    Rect& operator= ( Rect const & ) = default;
    Rect& operator= ( Rect && ) = default;
};

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

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

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

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