views:

175

answers:

5

We know that compiler generates some member functions for user-defined class if that member functions are not defined but used, isn't it. So I have this kind of code:

class AA
{
};

void main()
{
    AA a;
    AA b(a);
    a = b;
}

This code works fine. I mean no compiler error. But the following code....

class AA
{
    int member1;
    int member2;
};

But this code gives an run time error, because variable "a" is used without being iniltialized!!!

So my question is this: when we instantiate an int, it has a value. So why the default constructer doesn't work and by using those two int numbers initializes variable "a"??

EDIT: Platform: Win Vista, Compiler: Visual Studio 2008 compiler; Flags: Default

A: 

What platform? compiler? compiler flags? You must have some extra checking being added because there is nothing in normal C++ that checks initialization status.

c-urchin
+6  A: 

The compiler-synthesised default constructor calls the default constructors for all class members that have constructors. But integers don't have constructors, and so are not initialised. However, I find it hard to believe that this will cause a run-time error.

To initialise those variables:

class AA {
  public:
     AA() : member1(0), member2(0) {}
  private:
    int member1;
    int member2;
};
anon
+1, the level of effort to initialize the member variables is minimal and much cleaner.
Robb
A: 

In fact, the default and copy constructors do work. But in cpp uninitialized variables actually contain garbage. Therefore, you get your error (int member1, int member2 contains trash and you try to assign this trash to b object).

Kotti
How does it understands that it is trash not a value I have assigned??
Narek
@Narek some C++ compilers, when building code for debugging, will fill uninitialized variables with a special value (I think Visual C++ uses 0xCDCDCDCD) that allow it to detect this. My guess is the compiler-generated copy constructor checks the fields of the object it is copying to try to catch this type of error. Don't depend on this in release builds, though: in release builds they'll just contain whatever data was in that memory already.
Nick Meyer
0xCDCDCDCD is only used to fill heap allocations, not stack (local variables). And an int with a 0xCDCDCDCD value is a valid (-842150451), dereferencing a pointer with 0xCDCDCDCD would trap, but not using an int.
progrmr
A: 

Firstly, When you instantiate an int without initializing it, it has an indeterminate value. A built-in basic type does not have a constructor.

Secondly, that code should not generate a runtime error. It just copies indeterminate int values in the autogenerated copy constructor and assignment operators. It should generate a compiler warning that an uninitialized variable is being used.

Thirdly, your signature for main is wrong - the correct signature is

int main(void)
MadKeithV
Does it change something, when you write int main(void), instead of int main()???
Narek
It becomes correct according to the C++ standard :)Otherwise, not a lot changes - but you can use the return value to specify success or failure, useful for "chaining" programs.
MadKeithV
Narek, there is no difference between int main(void); and int main(); but you should not use void main()
mt_serg
Excuse me, who is forcing me to do that?? I will not use some dogmatic syntax, with no reason!
Narek
The C++ standard is forcing you to do that. If you think that's "no reason", perhaps you should switch to a different language.
MadKeithV
+1  A: 

Firstly, from practical point of view this is not a genuine run-time error. This is a built-in debugging feature of your development environment. The compiler attempts to catch situations when your read an uninitialized value, which is exactly what happens in your case.

Secondly, when we "instantiate" an int, it doesn't have a value. More precisely, it contains an undetermined value which is not even guaranteed to be stable (you can get different values by reading the same uninitialized variable several times in a row). Theoretically, reading an uninitialized int variable leads to undefined behavior, since it might contain an illegal ("trap") representation. In fact, you can perceive your "run-time error" generated by your development environment as a manifestation of that undefined behavior.

AndreyT
Within a function call uninitialized local variables are stable (they won't vary), but each call to a function re-allocates the locals and they get whatever values happen to be in the stack memory at the time. Also, an int cannot contain a trap representation, all values of an int are valid, you just don't know what value you'll get when it's uninitialized.
progrmr
@kk6yb: No, absolutely incorrect. Firstly, they are not stable in general case. Language makes no such guarantees and actually the instablity is often reproducible in practice. The instability occurs in practice when the variable is represented by a CPU register and then accessed outside of it "value lifetime", i.e. when the register is actually used for another variable. Stack memory has very little to do with it in general case.
AndreyT
@kk6yb: Secondly, the only type in C++ that cannot contain a trap representation is `unsigned char` (i.e. all bit patterns are valid). All other types, including `int` can contain a trap representation.
AndreyT
@AndreyT: I'll accept the first point, with optimization of locals into registers their values might not be stable throughout a function invocation.
progrmr