Синтаксис конструктора C++

простой вопрос: эквивалентны ли следующие утверждения? или второй делает более неявные вещи за кулисами (если да, то что?)

myClass x(3);
myClass x = myClass(3);

спасибо!

4 ответов


Они не полностью идентичны. Первая называется "прямая инициализация", а вторая - "инициализация копирования".

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

Итак, с этой точки зрения оба называются в одном - первом - правиле. В том случае, когда вы имейте инициализацию копирования с тем же типом, компилятору разрешено извлекать копию, поэтому он может построить временный, который вы создаете непосредственно в инициализированный объект. Таким образом, вы можете закончить очень хорошо с тем же кодом, сгенерированным. Но конструктор копирования, даже если копия удалена (оптимизирована), все равно должен быть доступен. Т. е. если у вас есть частный конструктор копирования, этот код недействителен, если код, в котором он появляется, не имеет к нему доступа.

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

myclass c = 3;

компилятор создает временный объект типа myclass, когда есть конструктор, который принимает int. Затем он инициализирует объект с этим временным. Также в этом случае временное созданное может быть создано непосредственно в инициализированном объекте. Вы можете следовать этим шагам мимо печать сообщений в конструкторах / деструкторах вашего класса и использование опции -fno-elide-constructors для GCC. Тогда он не пытается избавиться от копий.

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


второй может или не может вызвать дополнительный myclass построение объекта, если копирование elision не реализовано компилятором. Однако большинство конструкторов по умолчанию включают copy elision даже без какого-либо переключателя оптимизации.

Примечание инициализация при построении никогда не вызывает оператор присваивания.

всегда имейте в виду:

назначение: уже присутствующий объект получает новый значение

инициализации: новый объект получает значение в момент его рождения.


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


Я написал следующее, чтобы попытаться иллюстрации понять, что происходит:

#include <iostream>

using namespace std;

class myClass
{
public:
    myClass(int x)
    {
        this -> x = x;
        cout << "int constructor called with value x = " << x << endl;
    }

    myClass(const myClass& mc)
    {
        cout << "copy constructor called with value = " << mc.x << endl;
        x = mc.x;
    }

    myClass & operator = (const myClass & that)
    {
        cout << "assignment called" << endl;
        if(this != &that)
        {
            x = that.x;
        }
        return *this;
    }

private:
    int x;
};

int main()
{
    myClass x(3);
    myClass y = myClass(3);
}

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

$ ./a.out
int constructor called with value x = 3
int constructor called with value x = 3

Это кажется, чтобы указать, что нет никакой разницы между двумя звонки, сделанные в функции main, но это было бы неправильно. As litb указал, конструктор копирования должны быть доступным для работы этого кода, даже если он в этом случае он скрывается. Чтобы доказать это, просто переместите конструктор копирования в коде выше в закрытый раздел определения класса. Вы должны увидеть следующую ошибку:

$ g++ myClass.cpp 
myClass.cpp: In function ‘int main()’:
myClass.cpp:27: error: ‘myClass::myClass(const myClass&)’ is private
myClass.cpp:37: error: within this context

Также обратите внимание, что оператор присваивания имеет вид никогда называется.