Конструктор копирования класса шаблона не вызван

Мой конструктор копирования не вызывается, и я не знаю почему. Вот мой код:

template <typename T>
class SmartPtr
{
public:
explicit SmartPtr(T *p) : m_p(p) { cout << "ctor" << endl; }
SmartPtr(const SmartPtr& p) : m_p(p.m_p) { cout << "copy ctor" << endl;}

private:
T* m_p;
};

int main()
{
SmartPtr<int> pt4 = SmartPtr<int>(new int);
}

Выход только «ctor». Похоже, используется конструктор копирования по умолчанию. Если я добавлю «явный», то он не скомпилируется, выдав ошибку:

"error: no matching function for call to ‘SmartPtr<int>::SmartPtr(SmartPtr<int>)’"

Что я здесь не так делаю?

2

Решение

Это то, что известно как Копировать Elision. Это хорошая оптимизация, когда копия явно не нужна. Вместо эффективного запуска кода:

SmartPtr<int> __tmp(new int);
SmartPtr<int> ptr4(__tmp);
__tmp.~SmartPtr<int>();

Компилятор может знать, что __tmp существует только для строительства ptr4и, следовательно, разрешено строить __tmp на месте в памяти, принадлежащей ptr4 как будто фактический исходный код был просто:

SmartPtr<int> ptr4(new int);

Обратите внимание, что вы можете сказать компилятору НЕ делать этого тоже. Например, на gcc вы можете передать -fno-elide-constructors и с этим единственным изменением (дополнительно регистрируя деструктор), теперь ваш код печатает:

ctor
copy ctor // not elided!
dtor
dtor      // extra SmartPtr!

Увидеть демонстрация.

В стандарте §12.8:

Такое исключение операций копирования / перемещения, называемое разрешением копирования, допускается при следующих обстоятельствах (которые могут быть объединены для удаления нескольких копий):

  • В return оператор в функции с типом возвращаемого класса, когда …
  • В вбрасывание выражение, когда …
  • когда временный объект класса, который не был связан со ссылкой (12.2), будет скопирован / перемещен
    для объекта класса с таким же cv-неквалифицированным типом, операция копирования / перемещения может быть опущена
    построение временного объекта непосредственно в цель пропущенного копирования / перемещения
  • когда Исключение декларирование обработчика исключений (статья 15) …
[Пример:

class Thing {
public:
Thing();
~Thing();
Thing(const Thing&);
};

Thing f() {
Thing t;
return t;
}

Thing t2 = f();

Здесь критерии для исключения могут быть объединены, чтобы исключить два вызова конструктора копирования класса Thing:
копирование локального автоматического объекта t во временный объект для возвращаемого значения функции f()
и копирование этого временного объекта в объект t2, Эффективно, строительство местного объекта t
может рассматриваться как непосредственная инициализация глобального объекта t2и уничтожение этого объекта произойдет в программе
выход. Добавление конструктора перемещения в Thing имеет тот же эффект, но это конструкция перемещения из
временный объект t2 это исключено. — конец примера ]

1

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


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector