Каковы все функции-члены, созданные компилятором для класса? Это случается все время? - PullRequest
58 голосов
/ 17 сентября 2010

Каковы все функции-члены, созданные компилятором для класса?Это случается все время?как деструктор.Меня интересует, создан ли он для всех классов и зачем нужен конструктор по умолчанию?

Ответы [ 5 ]

84 голосов
/ 17 сентября 2010

C ++ 98/03

Если они нужны,

  1. компилятор сгенерирует конструктор по умолчанию для вас, если вы не объявите какой-либо свой конструктор.
  2. компилятор сгенерирует для вас копию конструктор , если вы не объявите свой собственный.
  3. компилятор сгенерирует для вас копию оператора присваивания , если вы не объявите свой собственный.
  4. компилятор сгенерирует для вас деструктор 1027 *, если вы не объявите свой собственный.

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


C ++ 11

C ++ 11 добавляет следующие правила, которые также применимы к C ++ 14 (кредиты для towi, см. этот комментарий ) :

  • Компилятор генерирует move constructor if
    • пользователь не объявил копию конструктор и
    • пользователь не объявил копия оператор присваивания и
    • пользователь не объявил move оператор присваивания и
    • нет заявленного пользователем деструктора ,
    • это не помечено как удалено ,
    • и все члены и базы подвижны .
  • Аналогично для move оператор присваивания : генерируется, если пользователь не определен
    • пользователь не объявил копия конструктор и
    • пользователь не объявил копия оператор присваивания и
    • пользователь не объявил move конструктор и
    • не существует объявленного пользователем деструктора ,
    • это не помечено как удалено ,
    • и все члены и базы подвижны .

Обратите внимание, что эти правила немного сложнее правил C ++ 03 и имеют больше смысла на практике.

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

class Thing {
public:
    Thing();                        // default constructor
    Thing(const Thing&);            // copy c'tor
    Thing& operator=(const Thing&); // copy-assign
    ~Thing();                       // d'tor
    // C++11:
    Thing(Thing&&);                 // move c'tor
    Thing& operator=(Thing&&);      // move-assign
};

И в качестве дальнейшего прочтения, если вы начинающий на C ++, рассмотрите проект, который не требует от вас реализации какой-либо из последних пяти, или Правило нуля ( Мартиньо Фернандес ) .

2 голосов
/ 17 сентября 2010

Вы имеете в виду «определено» как «создано»?

$ 12.1 - "Конструктор по умолчанию (12.1), конструктор копирования и оператор копирования (12.8) и деструктор (12.4) являются специальными функциями-членами.

Если «создано» означает «определено», то вот важные части из стандарта C ++.

-Неявно объявленный конструктор по умолчанию для класса неявно определяется, когда он используется для создания объекта своего типа (1.8).

-Если в классе нет объявленного пользователем деструктора, деструктор объявляется неявно. Неявно объявленный деструктор неявно определяется, когда он используется для уничтожения объекта своего типа.

-Если определение класса явно не объявляет конструктор копирования, он объявляется неявно. Неявно объявленный конструктор копирования неявно определяется, если он используется для инициализации объекта его типа класса из копии объекта его типа класса или типа класса, производного от его типа класса).

-Если определение класса явно не объявляет оператор присваивания копии, он объявляется неявно. Неявно объявленный оператор присваивания копии неявно определяется, когда объекту его типа класса присваивается значение его типа класса или значение типа класса, производное от его типа класса.

1 голос
/ 17 сентября 2010

По умолчанию, если не реализовано пользователем, компилятор добавляет некоторые функции-члены в класс.Они называются большой четверкой:

  • конструктор по умолчанию
  • конструктор копирования
  • оператор копирования (присваивание)
  • деструктор

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

0 голосов

C ++ 17 Стандартный проект N4659

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 6.1 "Объявления и определения" содержит примечание, в котором, вероятно, обобщены все из них:

3 [Примечание: В некоторых случаях реализации C ++ неявно определяют конструктор по умолчанию (15.1), конструктор копирования (15.8), конструктор перемещения (15.8), оператор назначения копирования (15.8), оператор назначения перемещения (15.8),или деструктор (15.4) функций-членов.- конец примечания] [Пример: учитывая

#include <string>

struct C {
  std::string s;         // std::string is the standard library class (Clause 24)
};

int main() {
  C a;
  C b = a;
  b = a;
}

, реализация будет неявно определять функции, чтобы сделать определение C эквивалентным

struct C {
  std::string s;
  C() : s() { }
  C(const C& x): s(x.s) { }
  C(C&& x): s(static_cast<std::string&&>(x.s)) { }
  // : s(std::move(x.s)) { }
  C& operator=(const C& x) { s = x.s; return *this; }
  C& operator=(C&& x) { s = static_cast<std::string&&>(x.s); return *this; }
  // { s = std::move(x.s); return *this; }
  ~ C() { }
};

- конец примера]

Условия, при которых они объявляются, поясняются по адресу: Условия для автоматической генерации ctor по умолчанию / копирования / перемещения и оператора копирования / перемещения?

Отличный способ убедиться, чточто-то имеет значение по умолчанию, чтобы попытаться использовать = default, как объяснено в: Что означает «значение по умолчанию» после объявления функции класса?

Пример, приведенный ниже, делает это, итакже выполняет все неявно определенные функции.

#include <cassert>
#include <string>

struct Default {
    int i;
    Default()                          = default;
    Default(const Default&)            = default;
    Default& operator=(Default&)       = default;
    Default& operator=(const Default&) = default;
    Default(Default&&)                 = default;
    Default& operator=(Default&&)      = default;
    ~Default()                         = default;
};

struct Instrument {
    int i;
    static std::string last_call;
    Instrument()                             { last_call = "ctor"; }
    Instrument(const Instrument&)            { last_call = "copy ctor"; }
    Instrument& operator=(Instrument&)       { last_call = "copy assign"; return *this; }
    Instrument& operator=(const Instrument&) { last_call = "copy assign const"; return *this; }
    Instrument(Instrument&&)                 { last_call = "move ctor";  }
    Instrument& operator=(Instrument&&)      { last_call = "move assign"; return *this; }
    ~Instrument()                            { last_call = "dtor"; }
};
std::string Instrument::last_call;

int main() {
    // See what the default constructors are doing.
    {
        // Default constructor.
        Default ctor;
        // i is uninitialized.
        // std::cout << ctor.i << std::endl;
        ctor.i = 1;

        // Copy constructor.
        Default copy_ctor(ctor);
        assert(copy_ctor.i = 1);

        // Copy assignment.
        Default copy_assign;
        copy_assign = ctor;
        assert(copy_assign.i = 1);

        // Copy assignment const.
        const Default const_ctor(ctor);
        Default copy_assign_const;
        copy_assign_const = const_ctor;
        assert(copy_assign_const.i == 1);

        // Move constructor.
        Default move_ctor(std::move(ctor));
        assert(move_ctor.i == 1);

        // Move assignment.
        Default move_assign;
        move_assign = std::move(ctor);
        assert(move_assign.i == 1);
    }

    // Check that the constructors are called by these calls.
    {
        // Default constructor.
        Instrument ctor;
        assert(Instrument::last_call == "ctor");

        // Copy constructor.
        Instrument copy_ctor(ctor);
        assert(Instrument::last_call == "copy ctor");

        // Copy assignment.
        copy_ctor = ctor;
        assert(Instrument::last_call == "copy assign");

        // Copy assignment const.
        const Instrument const_ctor(ctor);
        Instrument copy_assign_const;
        copy_assign_const = const_ctor;
        assert(Instrument::last_call == "copy assign const");

        // Move constructor.
        Instrument move_ctor(std::move(ctor));
        assert(Instrument::last_call == "move ctor");

        // Move assignment.
        Instrument move_assign;
        move_assign = std::move(ctor);
        assert(Instrument::last_call == "move assign");

        // Destructor.
        {
            Instrument dtor;
        }
        assert(Instrument::last_call == "dtor");
    }
}

GitHub upstream .

Протестировано с GCC 7.3.0:

g++ -std=c++11 implicitly_defined.cpp
0 голосов
/ 17 сентября 2010

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

Меня беспокоит, создан ли он для всех классов ...

Почему это касается? Думаете, это создает нежелательный код в исполняемом файле? Маловероятно, но вы можете легко проверить с вашей средой.

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

... а зачем нужен конструктор по умолчанию?

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

struct X
{
    std::string a;
    std::string b;
};

... деструктор по умолчанию обеспечивает работу деструкторов a и b.

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