C ++:函数主体中的顺序重要吗

时间:2018-10-26 01:19:42

标签: c++ class

#include <iostream>
using namespace std;

class A{
public:
   int data[3];
private:
   int cnt;
public:
   void put(int v){data[cnt++]=v;}
   int take(){int c=cnt;cnt=0;return c;}
};

int main() {
    A a;
    a.take();
    a.put(a.take());
    a.put(1);
    cout<<a.data[0];
    return 0;


}

我理解了大部分代码,但是我对函数a.take()感到困惑。在主函数中,我们首先创建一个对象a。然后我们运行a.take()。在此函数中,我们首先让c = cnt,然后将cnt赋值为0。

为什么在为c分配了尚无值的cnt值时没有错误。

如果将此函数写为     int take(){cnt = 0; c = cnt; return c;}

3 个答案:

答案 0 :(得分:2)

该代码的作者相信,使用对take()的初始调用来建立cnt的{​​{1}}成员值是符合标准的;他们错了(至少通过C ++ 14,我没有检查过C ++ 17)

按照标准

  

8.5初始化程序[dcl.init]

     
      
  1. 如果未为对象指定初始化程序,则该对象将被默认初始化。用自动或   获得动态存储持续时间,对象具有不确定性   值,如果没有对该对象执行初始化,则表明   对象保留不确定的值,直到该值被替换   (5.18)。 [注意:具有静态或线程存储持续时间的对象是   零初始化,请参阅3.6.2。 —尾注] 如果不确定的值是   评估产生的行为是不确定的,除了   以下情况:
  2.   

所有例外都不适用于您,因此我没有显示它们,但您可以查找它们以进行确认。

执行此操作的正确方法是在首次使用之前为0建立确定值(例如成员初始化列表),然后可以删除无用的cnt调用。换句话说,

take()

答案 1 :(得分:1)

我们来看看main()

  1. A a;

在此步骤中,您创建了类型为a的对象A

a中有什么?

(1)一个名为data的公共数据成员,它是int的数组。

(2)名为cnt的私有数据成员,它是int

请注意,在此步骤中,对象a已具有这两个数据成员。

它们的价值是另一回事。

(3)公共职能成员take()put()

  1. a.take()

现在您已经创建了a,就可以使用它。

a.take()调用take()a的public成员函数。

take()的正文中

int c=cnt;cnt=0;return c;
在返回之前,

ccnt的私有数据成员a的值初始化。

因此可以归结为一个问题:cnt在这一点上的价值是什么?

您的问题:

  

为什么在为c分配了尚无值的cnt值时没有错误。

您的措辞不正确。 cnt确实有价值。但是,在这种情况下,该值是不确定的。也就是说,可以是任何东西。可以是0、42或-123。

详细信息:

  1. 由于您没有为类A()提供默认构造函数A,因此编译器将为A生成综合的默认构造函数,该构造函数用于构造{{1 }}。

  2. 由于您没有为a提供类内初始化程序(例如cnt),因此默认构造函数将默认初始化int cnt = 0;

  3. 由于cntcnt,它是内置类型,因此内置类型的默认初始化规则表示:已定义内置类型的变量函数内部未初始化。内置类型的未初始化变量的值是不确定的。

  4. 由于int是在函数a中定义的,因此main()具有未定义的值。

答案 2 :(得分:0)

由于cnt是成员变量(非全局变量),因此其值未初始化,这意味着它可能是该内存位置中的任何值。使用它不是一个错误,但是它将读取的值实际上是垃圾。

请注意,全局变量和静态变量均初始化为0