Бесконечный цикл в конструкторе без или в течение
Я сделал тест здесь, но вывод - это цикл без конца, я не знаю почему.
На самом деле, я делаю еще один тест, но когда я написал это, я не понимаю, как произошел цикл. Он выводит "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)
, создавая неназванный временной, который снова вызывает конструктор по умолчанию.