конструктор по умолчанию — Какую функцию C ++ пишет и вызывает в пустом классе?

В книге Эффективный C ++, Я видел отрывок ниже:

В результате, если вы напишите

class Empty{};

это по сути так же, как если бы вы написали это:

class Empty {
public:
Empty() { ... }
Empty(const Empty& rhs) { ... }
~Empty() { ... }
Empty& operator=(const Empty& rhs) { ... } // copy assignment operator
};

Следующий код вызовет создание каждой функции:

Empty e1;
Empty e2(e1);
e2 = e1;

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

Вот основной код сборки:

00000000004006cd <main>:
4006cd:       55                      push   %rbp
4006ce:       48 89 e5                mov    %rsp,%rbp
4006d1:       b8 00 00 00 00          mov    $0x0,%eax
4006d6:       5d                      pop    %rbp
4006d7:       c3                      retq

Там нет ни одной функции с именем «Пусто» в .text сегмент.

Тогда каково поведение компилятора после того, как мы вызовем конструктор или присваивание пустого класса? Создает ли он некоторые функции, как сказано в книге? Если да, где они хранятся?

43

Решение

Функции существуют, но могут быть встроенными.

Когда компилятор включает функции, он понимает, что они не используются, и код не генерируется.

То, что говорится в книге, в некоторой степени верно, условные функции создаются компилятором для встроенного и прямого вызова.

Но сгенерированный код пуст, поэтому оптимизирующий компилятор затем удалит все свидетельства функции (установив указатель this), и функции никогда не будут вызываться напрямую.

Книга на самом деле не пытается объяснить сгенерированный код, а о влиянии создания класса и «скрытых» функций, которые он генерирует для нормальной работы.

54

Другие решения

Эти методы действительно генерируются для класса, но они генерируются как «встроенные».

Так как они являются реализациями «член за элементом» (например, конструктор копирования будет копировать-конструировать всех членов), когда class пусто, тогда в них фактически ничего не делается, а будучи встроенными, они просто невидимы.

Однако очень важно помнить, что эти методы автоматически получают реализацию … например, код

struct Foo {
char *buf;
Foo() : buf(new char[10]) {}
~Foo() { delete[] buf; }
};

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

Это глючит не из-за того, что было написано, а из-за того, что имеет не было написано, и это сложно. Вот почему крайне важно помнить, что C ++ напишет для вас автоматически: если эта реализация — то, что вы хотите, то идеально, но если нет, то исправьте ее, предоставив правильную реализацию или запретив создание или использование этого неправильного кода.

21

Вы и книга приходите в этой ситуации с разных уровней абстракции.

В книге термин «сгенерированный» используется для обозначения функций C ++, которые неявно определяются компилятором в абстрактную программу C ++. Это действительно происходит.

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

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

9
По вопросам рекламы [email protected]