Вот код, который производит различный вывод в g ++ 4.7 и vs2012 (cl17).
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "1" << endl; }
~A() { cout << "2" << endl; }
};
class B : public A
{
public:
B() { cout << "3" << endl; }
~B() { cout << "4" << endl; }
};
void func(A a) {}
int main()
{
B b;
func(b);
return 0;
}
Выход GCC 13242
пока cl выводит 132242
,
Почему компилятор cl производит второй A
объект, пока он делает копию в стеке, и для какой цели?
Кажется, это ошибка компилятора.
Стандарт C ++ не использует термин Нарезка объектов, Вы передаете объект типа B
к функции, которая получает параметр типа A
, Компилятор применит обычное разрешение перегрузки, чтобы найти соответствующее совпадение. В этом случае:
Базовый класс A
имеет предоставленный компилятором конструктор копирования, который будет принимать ссылку на A
и в отсутствие других функций преобразования это лучшее совпадение и должно использоваться компилятором.
Обратите внимание, что если бы было доступно лучшее преобразование, оно использовалось бы. Например: если A
был конструктор A::A( B const& )
, в дополнение к конструктору копирования, вместо конструктора копирования будет использоваться этот конструктор.
Компилятор C ++ будет синтезировать конструктор копирования по умолчанию в следующей ситуации. (Изнутри объектной модели C ++)
Мы видим, что класс А не в 4 ситуациях. Так что cl НЕ синтезирует конструктор копирования по умолчанию для него. Может быть, поэтому 2 временных объекта А построены и уничтожены.
Из окна дизассемблирования, мы видим следующий код, без вызова A :: A. :
B b;
00B317F8 lea ecx,[b]
00B317FB call B::B (0B31650h)
00B31800 mov dword ptr [ebp-4],0
func(b);
00B31807 mov al,byte ptr [ebp-12h]
00B3180A mov byte ptr [ebp-13h],al
00B3180D mov byte ptr [ebp-4],1
00B31811 movzx ecx,byte ptr [ebp-13h]
00B31815 push ecx
00B31816 call func (0B31730h)
Но если мы сделаем деструктор виртуальным. Мы получим следующий код дизассемблирования, мы увидим, что A :: A вызывается. Тогда результат, как и ожидалось, только 1 объект создан.
B b;
00331898 lea ecx,[b]
0033189B call B::B (03316A0h)
003318A0 mov dword ptr [ebp-4],0
func(b);
003318A7 push ecx
003318A8 mov ecx,esp
003318AA mov dword ptr [ebp-1Ch],esp
003318AD lea eax,[b]
003318B0 push eax
003318B1 call A::A (0331900h)
003318B6 mov dword ptr [ebp-20h],eax
003318B9 call func (03317D0h)
Вы столкнулись с ошибкой компилятора.
Надлежащая функциональность объясняется ниже:
Функция func
Нужно создать копию объекта (но будьте осторожны с нарезкой).
Итак, что происходит, это:
int main()
{
// create object B, which first creates the base object A
B b;
// create object A, using this copy constructor : A( const B& )
func(b);
}
Дополнительный вызов ~ A () выполняется, когда созданный копией объект A уничтожается в конце func
вызов.