8

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;
}
12
  • 1
    Both work (error-wise) on GCC 4.7.2 and Clang 3.2. Commented Feb 1, 2013 at 5:48
  • @chris: Oh weird, I was using Visual C++. In that case, which one is right?! Commented Feb 1, 2013 at 5:49
  • 1
    I'm not sure, but I'd wager a guess on GCC and Clang over MSVC almost any day. At least it narrows down the problem a bit. Commented Feb 1, 2013 at 5:49
  • 1
    Actually both should compile. A code like int a=a+100; and int a(a+100); is fine from syntax point of view. They might invoke UB depending on whether they're created in static storage duration or automatic storage duration. Commented Feb 1, 2013 at 5:49
  • 1
    What has the assignment operator got to do with anything in the example? And I would never describe this as "severe" because it only affects really silly code. Commented Feb 1, 2013 at 11:37

2 Answers 2

4

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:

Sign up to request clarification or add additional context in comments.

5 Comments

What if a is previously defined as something else, like, say, a class? Is it still fine?
@Mehrdad: That is redeclaration, no?
Maybe in a different scope, yeah. But my question is, would the a on the right-hand side be referring to the old a or the new a?
@Mehrdad: It refers to the new a : the part int a declares a variable, which hides any symbol with same name declared in outer scope, then =a+100 is the initializer part.
Huh... +1 interesting, thanks for the answer. On another note, this "would you like to move this discussion to chat?" thing is popping up waaaaay too early...
1

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); }
             ^

1 Comment

thanks for the insight again :-). now i know it is a known bug :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.