Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding copy-initialization in C++, compared to explicit initialization

Why does the first commented line compile correctly, whereas the second doesn't?

Why can a be given itself as a constructor argument, but b can't?
Aren't the two doing the same thing?

class Foo { Foo &operator =(Foo const &); /* Disable assignment */ };

int main()
{
    Foo a = a;  // OK
    Foo  b(b);  // error C2065: 'b' : undeclared identifier
}

Update

Since it seems like it's compiler-dependent, it seems like the problem is more severe than I thought.
So I guess another part of the question is, is the following code valid or no?

It gives an error in GCC but Visual C++ executes it just fine.

int main()
{
    int i = 0;
    { int *i(&i); }
    return i;
}
like image 821
user541686 Avatar asked Feb 01 '13 05:02

user541686


2 Answers

In your first code, both declarations should compile. GCC is right there. Visual C++ Compiler has bug.

And in the second code, the inner declaration should not compile. GCC is right there too, and VC++ is wrong.

GCC is right in both cases.

A code like int a=a+100; and int a(a+100); is fine from syntax point of view. They might invoke undefined behavior depending on whether they're created in static storage duration or automatic storage duration.

int a = a + 100; //well-defined. a is initialized to 100
                 //a on RHS is statically initialized to 0
                 //then a on LHS is dynamically initialized to (0+100).
void f()
{
   int b = b + 100; //undefined-behavior. b on RHS is uninitialized

   int a = a + 50; //which `a` is on the RHS? previously declared one?
                   //No. `a` on RHS refers to the newly declared one.
                   //the part `int a` declares a variable, which hides 
                   //any symbol with same name declared in outer scope, 
                   //then `=a+50` is the initializer part.
                   //since a on RHS is uninitialized, it invokes UB
}

Please read the comments associated with each declaration above.

Note that variables with static storage duration is statically initialized to zero at compile time, and if they've initializer, then they're dynamically initialized also at runtime. But variables of POD types with automatic storage duration are not statically initialized.

For more detail explanation on static initialization vs dynamic initialization, see this:

  • What is dynamic initialization of object in c++?
like image 94
Nawaz Avatar answered Oct 21 '22 18:10

Nawaz


In your first example, as you note, the behavior is undefined even though the syntax is okay. A compiler is therefore permitted to refuse the code (the undefined behavior must be guaranteed however; it is here, but it wouldn't be if the invalid initializations were never actually executed).

Your second example has a type error: A declaration is visible as soon as its declarator is seen, and in particular it is visible in its own initializer. MSVC++ delays the visibility: That's a known non-conformance issue in that compiler. E.g., with the EDG compiler (which has a Microsoft mode):

$ ./cfe --strict x.c
"x.c", line 4: error: a value of type "int **" cannot be used to initialize an
          entity of type "int *"
      { int *i(&i); }
               ^

1 error detected in the compilation of "x.c".
$ ./cfe --microsoft x.c
"x.c", line 4: warning: variable "i" was declared but never referenced
      { int *i(&i); }
             ^
like image 31
user1056575 Avatar answered Oct 21 '22 16:10

user1056575