构造函数中的无限循环,不带或不带

时间:2013-04-24 19:51:50

标签: c++ recursion constructor const

我在这里做了一个测试,但输出是一个没有结束的循环,我不知道为什么。

实际上,我正在做另一个测试,但是当我写这个时,我不明白循环是如何发生的。它反复输出“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;  
}

4 个答案:

答案 0 :(得分:94)

这里的问题是编译器解释

test(_b);

不是创建传递参数test的{​​{1}}类型的临时对象的代码,而是作为类型为_b的名为_b的变量的变量声明,使用默认构造函数。因此,看起来像是使用第二个构造函数创建临时test对象的代码,而是递归地创建类型为test的新对象并再次调用构造函数。

要解决此问题,您可以为变量指定显式名称,例如

test

这只能被解释为名为test t(_b); 的{​​{1}}类型的变量,使用第二个构造函数进行初始化。

我以前从未看过这个,我已经用C ++编程多年了。感谢您向我展示该语言的另一个角落案例!

官方解释:根据C ++ 03 ISO规范,§6.8:

  

涉及表达式语句和声明的语法存在歧义:具有函数式显式类型转换(5.2.3)的表达式语句,因为其最左侧的子表达式与第一个声明符以第一个声明符开头的声明无法区分a(。在这些情况下,声明是声明。

(我的重点)。换句话说,任何时候C ++都可以将语句解释为表达式(临时对象强制转换)或声明(变量),它将选择声明。 C ++规范明确给出了

  

T(一);

作为声明的示例,而不是testt类型的演员。

这是C ++的Most Vexing Parse - 看起来像表达式而是被解释为声明。我之前见过MVP,但在这种情况下我从未见过它。

希望这有帮助!

答案 1 :(得分:0)

问题来自构造函数,你再次调用了构造函数test(_b)

  

测试::测试(){的std :: COUT&LT;&LT; “ABC”; _ b.clear(); _ B [1] = 1;试验(_b);}

这是发生的事情

每次调用test(_b)时,它首先调用默认构造函数test :: test,然后轮流调用test(_b),循环继续,直到堆栈溢出。

从默认构造函数

中删除测试(_b)

答案 2 :(得分:0)

我不熟悉标准的特性,但可能是在构造函数中调用构造函数是未定义的。因此,它可能依赖于编译器。在这种特殊情况下,它会导致默认构造函数的无限递归,而不会使用map参数调用构造函数。

C ++ FAQ 10.3有一个带有两个参数的构造函数的例子。如果将int参数添加到第二个构造函数(例如test(map, int)),则表现出一些正常的行为。

对于良好的表单,我只需将test::test(std::map <int, int>& im)更改为test::testInit(std::map <int, int>& im),将test(_b)更改为testInit(_b)

答案 3 :(得分:0)

我很确定你实际上并没有“调用构造函数”,因为它们不能直接调用IIRC。 legalese必须与构造函数不是命名函数 - 我没有标准方便的副本或我可能引用它。我相信你正在使用test(_b)创建一个未命名的临时函数,它再次调用默认构造函数。