Бесконечный цикл в конструкторе без или в течение

Я сделал тест здесь, но вывод - это цикл без конца, я не знаю почему.

На самом деле, я делаю еще один тест, но когда я написал это, я не понимаю, как произошел цикл. Он выводит "ABC" несколько раз.

#include <map>
#include <string>
#include <iostream>

class test
{
public:
   std::map <int, int> _b;
   test();
   test (std::map<int, int> & im);
   ~test();
   };

test::test()
{
  std::cout<<"abc";
  _b.clear();
  _b[1]=1;
  test(_b);
}

test::test(std::map <int, int>& im)
{
   std::cout<<im[1];
}

test::~test() {};

int main ()
{
   test a;  
}

Ответ 1

Проблема здесь в том, что компилятор интерпретирует

test(_b);

Не как код, создающий временный объект типа test, проходящий в параметре _b, но как объявление переменной для переменной с именем _b типа test, используя конструктор по умолчанию. Следовательно, то, что выглядит как фрагмент кода, создающий временный объект test с использованием второго конструктора, вместо этого рекурсивно создает новый объект типа test и вызывает конструктор в другое время.

Чтобы исправить это, вы можете указать переменной явное имя, например

test t(_b);

Это можно интерпретировать только как переменную типа test с именем t, инициализированную с использованием второго конструктора.

Я видел никогда, и я программировал на С++ годами. Спасибо, что показал мне еще один угловой случай языка!

Для официального объяснения: Согласно спецификации С++ 03 ISO, & sect; 6.8:

Существует неоднозначность в грамматике, включающая выражения-утверждения и декларации: выражение-выражение с преобразованием явного типа в стиле функции (5.2.3) как его самое левое подвыражение может быть неотличимым от объявления, в котором первый декларатор начинается с a (. В этих случаях утверждение является объявлением.

(Мой акцент). Другими словами, в любой момент, когда С++ мог интерпретировать оператор как выражение (временный объект) или как объявление (переменной), он выберет объявление. Спецификация С++ явно дает

Т (а);

В качестве примера объявления, а не приведения a к типу t.

Это С++ Самый Vexing Parse - то, что выглядит как выражение, вместо этого интерпретируется как объявление. Я видел MVP раньше, но я никогда не видел его в этом контексте.

Надеюсь, это поможет!

Ответ 2

проблема заключается в том, что вы снова вызываете конструкторский тест (_b)

тест:: тест() {станд:: соиЬ < < "ABC"; _ b.clear(); _ Ь [1] = 1; тест (_b);}

вот что происходит

каждый раз, когда вы вызываете test (_b), он сначала вызывает стандартный конструктор test:: test, и он поочередно вызывает тест (_b), и цикл продолжается и продолжается до тех пор, пока стек не переполнится.

удалите тест (_b) из конструктора по умолчанию

Ответ 3

Я не знаком с особенностями стандарта, но может быть, что вызов конструктора внутри конструктора undefined. Таким образом, он может быть зависимым от компилятора. В этом конкретном случае это вызывает бесконечную рекурсию вашего конструктора по умолчанию, даже не называя ваш конструктор аргументом карты.

С++ Часто задаваемые вопросы В 10.3 приведен пример с конструктором с двумя параметрами. Если вы добавите параметры int ко второму конструктору, например test(map, int), он проявит несколько нормальное поведение.

Для хорошей формы я просто изменил бы test::test(std::map <int, int>& im) на test::testInit(std::map <int, int>& im) и test(_b) на testInit(_b).

Ответ 4

Я уверен, что вы на самом деле не называете конструктор, поскольку они не могут быть напрямую вызваны IIRC. Легализация была связана с тем, что конструкторы не называются функциями - у меня нет копии стандарта, или я могу ее процитировать. Я полагаю, что вы делаете с test(_b), создавая неназванный временной, который снова вызывает конструктор по умолчанию.