Что происходит за кулисами при ручном вызове конструктора в C ++? - PullRequest
3 голосов
/ 07 августа 2020

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

SomeClass x(arg1, arg2, arg3);  // An instance of SomeClass is constructed.

x = SomeClass(arg4, arg5, arg6);  // Intent is to create a new instance.

SomeClass не не реализовано operator=.

Пространство, выделенное для x, просто перезаписывается, как если бы оно было недавно выделенной памятью, или что именно происходит? А когда это хорошая идея?

Ответы [ 2 ]

4 голосов
/ 07 августа 2020

Это лучше всего можно объяснить на небольшом примере:

Live on Coliru

struct A {
  A(int a) { cout << "A::ctor\n"; }                      //ctor
  A(const A& a) { cout << "A::copy\n"; }                 //copy ctor
  A& operator=(const A& a) { cout << "A::operator=\n"; } //copy assign
};

int main()
{
    A a(2);     //calls constructor
    a = A(10); //calls constructor first, then copy assignment
}

Вывод:

A::ctor
A::ctor
A::operator

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

SomeClass не реализован operator=.

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

(я настоятельно рекомендую вам прочитать Правило трех / пяти / нуля и понять его. Оно входит в число лучших 5 вещей в C ++, которые вы должны знать.)

    A& operator=(const A& a) = delete; //copy assign deleted
    A& operator=(A&& other) { cout << "move assigned\n"; } //move assign available

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

    A a(2);           //ctor
    a = A(10);        //ctor + move assign
    A b(3);           //ctor
    b = a;            // copy assign only
    a = std::move(b); // move assign

Для a = A(10) move assign вызывается, потому что A(10) - это rvalue того же типа, что и то, что находится слева от =.

В последнем случае a = std::move(b); мы явно приводим b к rvalue (да, это то, что делает std::move()). Поскольку теперь это rvalue, вызывается присвоение перемещения.

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

  • Сначала создается временное: A(10). Разумеется, для него будет выделено пространство.
  • Его результат затем присваивается a, поэтому предыдущие значения в a перезаписываются
  • деструктор для временного будет вызываться

И когда это хорошая идея?

Это хорошая идея, когда она вам нужна, это зависит от вашего сценария использования. Как правило, я бы рекомендовал не копировать assign без надобности.

1 голос
/ 07 августа 2020

Вторая строка - это вызов конструктора, за которым следует вызов оператора присваивания. Назначение по умолчанию мелкой копии нестатических c элементов в существующее хранилище.

Если вы определили что-то, что мешает компилятору создать operator= по умолчанию, т.е. вы определили конструктор перемещения или назначение перемещения, назначение невозможно если вы не объявили свое собственное (почему это так удивительно?). Если неглубокая копия по умолчанию подходит, вы можете написать следующее объявление:

SomeClass& operator(const SomeClass&) = default;

= default обеспечивает механизм для объявления поведения специальных функций по умолчанию.

Теперь есть назначение перемещения, и в таком случае было бы предпочтительнее, если бы оно было объявлено в данном контексте. Но он не будет объявлен компилятором, если пользователь предоставил деструктор или оператор копирования \ перемещения \ присваивания.

SomeClass& operator(SomeClass&&) = default;

Разница между двумя присваиваниями существует только для типов классов, где семантика «перемещения» может включать передачу владение. Для тривиальных типов и примитивных типов это простая копия. не изменит поведение программы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...