#c #copy-constructor #default-constructor #move-constructor #most-vexing-parse
#c #copy-constructor #default-constructor #переместить-конструктор #most-vexing-parse
Вопрос:
Ниже приведен фрагмент, предназначенный для тестирования конструкторов. Он был запущен в VS 2015.
На мой взгляд, «B b (B ())» имеет ту же функцию, что и «B b = B ()», однако мой код, похоже, говорит, что они ведут себя по-разному.
Я знаю, что оптимизация компилятора исключает копирование, но я думаю, что конструктор по умолчанию должен вызываться по крайней мере при выполнении «B b (B ())». Кто-нибудь может помочь указать, где я неправильно понял?
class B
{
public:
B() {
i;
x = new int[100];
cout << "default constructor!"<<" "<<i << endl;
cout << "x address:" << x << endl << "--------" << endl;
}
B(const B amp;b) //copy constructor
{
i;
cout << "Copy constructor amp; called " << i<< endl
<< "--------" << endl;
}
B(B amp;amp;b)//move constructor
{
x = b.x;
i;
b.x = nullptr;
cout << "Copy constructor amp;amp; called" << i << endl
<<"x address:"<< x << endl << "--------" << endl;
}
void print()
{
cout << "b address:" << x << endl << "--------" << endl;
}
private:
static int i;
int *x;
};
int B::i = 0;
int main()
{
B b1; //default constructor
b1.print();
B b2 = B(); //default constructor only
b2.print();
B b3(B()); //????nothing called... why???
B b4 = b2; //copy constructor
B b5 = move(b2); //move constructor
b2.print();
return 0;
}
Ответ №1:
Обратите внимание, что B b(B())
это объявление функции, а не определение переменной вообще, тогда конструктор не будет вызван.
Согласно наиболее неприятному синтаксическому анализу, B b(B())
это объявление функции для функции с именем b
, которая возвращает объект типа B
и имеет один (неназванный) параметр, который является указателем на функцию, возвращающую тип B
и не принимающую параметр.
Вы можете решить это с помощью фигурных скобок (инициализация списка (начиная с C 11)), например
B b1( B{} );
B b2{ B() };
B b3{ B{} }; // preferable from C 11
Комментарии:
1. Хороший улов! @Shirley Feng, согласно статье в вики, вы можете получить ожидаемое поведение, добавив круглые скобки вокруг вашего внутреннего вызова ctor . Пример:
B b3( (B()) );
2. Спасибо за сообщение!! Это спасает меня XD
3. Просто интересно, не лучше ли продолжать использовать одно соглашение для инициализации? т. е.
B b{ B{} };
вместо4. @AdrianShum Вы правы. Я просто хочу отметить, что только использование одной пары фигурных скобок разрешило бы двусмысленность здесь.
5. @ShirleyFeng Да! Это действительно важная функция C 11.