61

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

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

4 回答 4

94

这里的问题是编译器解释

test(_b);

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

要解决此问题,您可以为变量指定一个明确的名称,例如

test t(_b);

这只能解释为类型test为 named的变量t,使用第二个构造函数初始化。

我以前从未见过这种情况,而且我已经用 C++ 编程多年了。感谢您向我展示了该语言的另一个极端案例!

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

在涉及表达式语句和声明的语法中存在歧义:将函数样式显式类型转换 (5.2.3) 作为其最左侧子表达式的表达式语句与第一个声明符以 (.在这些情况下,声明就是声明。

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

T(一);

作为声明的示例,而不是a类型的转换T

这是 C++最令人烦恼的解析- 看起来像表达式的东西却被解释为声明。我以前见过 MVP,但我从未在这种情况下见过它。

希望这可以帮助!

于 2013-04-24T20:08:42.940 回答
0

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

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

这就是发生的事情

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

从默认构造函数中删除 test(_b)

于 2013-04-24T19:58:52.563 回答
0

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

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

对于良好的形式,我会简单地改变test::test(std::map <int, int>& im)fortest::testInit(std::map <int, int>& im)test(_b)to testInit(_b)

于 2013-04-24T19:59:05.170 回答
0

我很确定您实际上并没有“调用构造函数”,因为它们不能直接调用 IIRC。法律术语与未命名为函数的构造函数有关——我手边没有标准的副本,或者我可能会引用它。我相信你正在做的test(_b)是创造一个无名的一个临时的,它再次调用默认构造函数。

于 2013-04-24T20:09:20.717 回答