2010-05-17 2 views
5

Можете ли вы помочь мне там определение в стандарте C++, который описывает, который один будет называться конструктор или оператор присваивания в этом случае:Конструктор или Оператор присваивания

#include <iostream> 

using namespace std; 

class CTest 
{ 
public: 

CTest() : m_nTest(0) 
{ 
    cout << "Default constructor" << endl; 
} 

CTest(int a) : m_nTest(a) 
{ 
    cout << "Int constructor" << endl; 
} 

CTest(const CTest& obj) 
{ 
    m_nTest = obj.m_nTest; 
    cout << "Copy constructor" << endl; 
} 

CTest& operator=(int rhs) 
{ 
    m_nTest = rhs; 
    cout << "Assignment" << endl; 
    return *this; 
} 

protected: 
int m_nTest; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
CTest b = 5; 

return 0; 
} 

Или это просто вопрос оптимизации компиляторов?

+0

Может ли быть какая-либо разница между «CTest b (5)» и «CTest b = 5» в зависимости от компилятора? –

+0

Нет, первый синтаксис - это общий синтаксис C++ для создания экземпляра класса и предоставления аргументов конструктору. Второй синтаксис - это просто альтернативная формулировка, которую вы можете использовать, если конструктор принимает ровно один аргумент. Он существует, поэтому код C будет компилироваться без изменений. – eemz

+0

@joefis, почему вы даете вам ответ так же, как комментарий? Можете ли вы дать несколько доказательств того, что вы сказали? –

ответ

7

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

+1

Может ли быть какая-либо разница между «CTest b (5)» и «CTest b = 5» в зависимости от компилятора? –

+0

@ju Да, это то, что мы говорим. Первый не будет использовать конструктор копирования, второй может быть. –

+0

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

11

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

CTest b(5); 

Оператор присваивания никогда вызывается в инициализации. Рассмотрим следующий случай:

CTest b = CTest(5); 

Здесь мы вызываем конструктор (принимая int) явно и затем присвоить результат b. Но еще раз, никакой оператор назначения не , когда-либо вызывал. Строго говоря, оба случая вызывают конструктор копирования после создания объекта типа CTest. Но на самом деле стандарт активно побуждает компиляторы оптимизировать вызов конструктора копирования здесь (§12.8/15) - на практике современные компиляторы C++ не будут вызывать здесь вызов copycon.

+4

+1, но я постараюсь избежать «default» в предложении «конструктор по умолчанию, принимающий int». Я думаю, что будет проще сказать «конструктор int» или «конструктор, принимающий int». Значение по умолчанию имеет конкретное значение (без аргумента) в стандарте. –

+0

Оператор присваивания IS вызывается, если методы оператора конструктора и оператора присваивания отличаются от кода. – BJovke

+0

@BJovke No - никогда не в инициализации. –

4

CTest b = 5; - это точный эквивалент CTest b(CTest(5)); Приводятся два конструктора: один принимает int (неявное преобразование из целого числа 5) и конструктор копирования. Оператор присваивания здесь никак не связан.

Компилятор может оптимизировать ненужную копию, поэтому результат будет таким, как если бы вы набрали CTest b(5). Поэтому во время выполнения оба файла, видя «Конструктор копирования», напечатанный (GCC с опцией -fno-elide-constructors) или нет (по умолчанию GCC), будет действительным выходом программы.

Однако концептуально компилятор должен проверить, существует ли доступный и подходящий конструктор копирования. Форма CTest b = 5; не сможет скомпилировать, если: a) конструктор копирования является приватным/защищенным (не доступен) или b) конструктор копирования принимает аргумент с помощью неконстантной ссылки (не может принять временное значение от CTest(5) - VC++ может принять его как нестандартное расширение компилятора, хотя).

Мораль: нет простого способа определить, где и сколько раз конструктор копирования вызывается в программе, просматривая код. Копирование часто может быть опущено, и поэтому вы никогда не должны полагаться на побочные эффекты конструктора копирования. Если он делает то, что он должен делать, то для вас не должно иметь значения, если компилятор устраняет ненужные вызовы конструктора копирования.

Смежные вопросы