Конструктор или оператор присваивания - PullRequest
5 голосов
/ 17 мая 2010

Можете ли вы помочь мне, есть ли в стандарте 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;
}

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

Ответы [ 3 ]

11 голосов
/ 17 мая 2010

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

CTest b(5);

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

CTest b = CTest(5);

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

7 голосов
/ 17 мая 2010

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

4 голосов
/ 17 мая 2010

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

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

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

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

...