2013-05-10 129 views
1

只是偶然发现了这个问题,谁能解释一下这里发生了什么?为什么这个成员变量没有正确初始化?

struct Foo { 
    int i; 
    ~Foo() { 
     std::cout << i << std::endl; 
    } 
}; 

void bar() 
{ 
    Foo f; 
    f.i = 1; 
    f = Foo(); 
    f.i = 2; 
} 

我得到以下输出:

-85899... (gibberish = "default" value for uninitialized int) 
2 

,我预计

1 
2 

为什么是它f.i = 1;似乎这里有没有影响?

+6

因为f的析构函数,当你一个新的Foo值分配给它不会被调用。第一个输出可能来自f = Foo()中临时的析构函数。 – 2013-05-10 12:46:06

+3

@mfontanini没有未定义的行为。未初始化时'i'的值是不确定的。行为是定义的,但不是确定的。完全不同的两件事。 – pmr 2013-05-10 12:48:55

+0

你使用的是古老的编译器吗?自2003年以来(甚至可能是1998年),'Foo()'应该初始化临时值,并将'i'设置为'0'。 – 2013-05-10 13:20:03

回答

9

f.i = 1确实有效。它将成员i设置为等于1。你只会看到如果对象被销毁,因为你在析构函数中输出了这个值。

在行f = Foo();,你要创建一个临时Foo对象,它与不确定的价值i,然后将其分配给对象f。这个临时对象在行末被销毁,打印出自己不确定的i。这是什么给你-85899...输出。

将不确定的值复制到对象f,但随后使用值2覆盖其成员i。在bar结束时,此对象被破坏,您将看到输出2

+2

我不认为还有什么可以说的问题的代码段! +1 – 2013-05-10 12:50:47

+1

可能值得一提的是,一个相当现代的,没有bug的编译器应该对临时值进行初始化,并打印零点而不是垃圾。 – 2013-05-10 17:19:38

+0

@MikeSeymour C++不会使用简单的类型对成员变量进行初始化,除非您告诉它。这是设计 - 对它们进行值初始化需要时间,C++假设您不关心(并且不想浪费那段时间),除非另有说明。特别是,该值被认为是“不确定的”。 – 2013-05-13 17:19:32

11

因此,在第一次调用析构函数时销毁的变量不是f,而是由Foo()创建的临时变量。由于您没有构造函数,因此i具有不确定的值。如果你要添加一个将i设置为99999的构造函数,那么你会看到你的析构函数的输出。

void bar() 
{ 
    Foo f; // Construct f of type Foo 
    f.i = 1; // Set i to 1 in f. 
    f = Foo(); // Construct a temporary Foo object, copy it to f, 
       // then destroy the temporary object. 
    f.i = 2; // Set the newly copied f.i to 2. 
       // destroy f. 
} 
+0

+1解释为什么 – 2013-05-10 12:47:20

+0

第二行是什么原因? – Niko 2013-05-10 12:47:28

+2

@Niko - 你的范围/程序结尾的f的析构函数。 – 2013-05-10 12:48:04

4

这样的:

f = Foo(); 

创建一个新对象,并复制。那么这个对象在这行结束时就遭到了破坏,但它并没有被初始化。只是复制。

2

第一个输出来自临时调用的析构函数。默认赋值运算符不会调用任何析构函数,因此打印1的函数永远不会被调用。

一些代码来说明:

struct Foo { 
    int i; 
    // we emulate the default operator= generated by the compiler 
    // no check for self-assignment 
    Foo& operator=(const Foo& other) { this->i = other.i; } 
}; 

void bar() { 
    F f; 
    f.i = 1; 
    f = Foo(); // the i member of the temporary is indeterminate 
      // now f.i is indeterminate 
      // destroy the temporary 
    f.i = 2; 
} // end of scope, destroy f 
相关问题