I'm studying the Declarations in Conditions topics in C++ and faced the below problem.
#include <iostream>
int main() {
int x;
std::cin >> x;
if(int a = 4 && a != x) {
std::cout << "Bug fixed!" << std::endl;
}
}
I declared and then initialized the variable a. In the The C++ Programming Language by Bjarne Stroustrup Ed.2011, it is said:
The scope of variable declared in if statement extends from its point of declaration to the end of the statement that the condition controls.
That's what I did, I declared and initialized the variable a, but when I try to compare it against x, compiler gives uninitialized local variable a used error. Why, what's the problem?
I can do
int a = 4;
if (a != x)
// ...
but I would like to do it in one line if possible.
In the expression inside the if condition
int a = 4 && a != x
what the compiler actually sees is
int a = (4 && a != x)
where the value of a is clearly being used before it's initialized (which is what the error is saying), and is not the intent of the code.
From C++17, you can use if-with-initializer syntax to achieve the effect you want
if (int a = 4; a != x)
// ...
Related
This question already has answers here:
variable declaration within the while loop C/C++
(5 answers)
Closed 5 years ago.
Why does this code cause an infinite loop:
#include <iostream>
using namespace std;
int main() {
int y = 5;
while (y < 6) {
int y = 7;
cout << y << endl;
}
}
yet removing the "int" in the while statement makes it run once normally?
(
#include <iostream>
using namespace std;
int main() {
int y = 5;
while (y < 6) {
y = 7;
cout << y << endl;
}
}
)
In this loop:
while (y < 6) {
int y = 7;
cout << y << endl;
}
The inner y is not accessible in the condition test.
If you remove the int in the loop, you're simply assigning a new value to the variable defined outside while, thus terminating it.
Look up Scope on CppReference.
The behaviour you have observed is called shadowing.
This means that a variable is "shadowed" by another variable in an inner scope.
(iBug has already provided a link to the C++ scope rules)
The outer scope (in your case while(y < 6)) can not access the inner scope (in your case int y = 7;) and vice versa. Both have the same name, but they are completely separate variables in separate scopes.
This is a very common source for errors (you also find a lot of them here) and doesn't only happen with loops and other scope brackets, but also very often with class members. Imagine a class:
class MyClass {
int a;
public:
void getA( int a ) { return a; }
};
getA() defines a parameter a, which shadows the class member a. This is at least bad style, but even more probable a source of errors. We don't know - did you want to return the member a or did you really mean the parameter? So this should be avoided.
Here's a real life example on Stackoverflow - see my comment below the question (regarding the 3rd constructor)
Possibilities to avoid these kind of errors are:
Use highest possible compiler warnings and perhaps even warnings as errors. Compilers can warn about those kind of shadowing issues.
Use a name scheme. A common scheme is members with a m, m_ prefix, a _ suffix and the like. If the member name in the MyClass would have been m_a, this would have reduced confusion. Of course this doesn't help in your example, but it's a good idea nevertheless.
So if I initialize a variable of the same type and name within the main function the compiler will complain of the re declaration, for example:
for (int i = 0; i < 5; i++)
{
int a{5};
int a{5}; // error int a previously declared here
}
But there are no errors if I compile this instead:
for (int i = 0; i < 5; i++)
{
int a{5};
}
To my understanding, this looks as if I have initialized "int a" multiple times within the same scope which obviously would cause an error. If somebody could explain what's actually happening it would be greatly appreciated! Thanks!
You are confusing scope and lifetime, it seems.
for (int i = 0; i < 5; i++)
{
int a{5};
}
To my understanding, this looks as if I have initialized "int a"
multiple times within the same scope which obviously would cause an
error.
Why would that obviously cause an error? a is always the same variable, in every iteration of the loop. But it always points to a different object, whose lifetime begins and ends with the current iteration.
If such a thing would not work, then you could not even call the same function two times:
void f()
{
int x = 0;
}
f();
f(); // why should this be an error?
Note that this question goes far beyond g++, and even far beyond C++. Every C-derived programming language works exactly like that. At least I've never seen one which doesn't.
To my understanding, this looks as if I have initialized "int a" multiple times within the same scope
You are right about the "multiple times" part, but you are wrong about "same scope": the scope of the second int a is nested inside the outer scope, in which the first int a is declared. Hence, the second declaration is legal: it hides the outer declaration, which the language allows.
int a = 5;
cout << a << endl;
{
int a = 6;
cout << a << endl;
}
cout << a << endl;
Demo above produces this output:
5
6
5
I think your getting confused with declaring variable and initializing it
for (int i = 0; i < 5; i++)
{
int a{5}; // In this part you are declaring and initializing the variable
int a{5}; // error int a previously declared here
// same with this case as well
}
If you want to do that you can use this
for (int i = 0; i < 5; i++)
{
int a{5};
a=5; // error int a previously declared here
}
at this point int a{5} This will be the declaration of a variable and initialization of variable in the for loop scope
and a=5; and here reinitialize that particular variable in the same scope
This question already has answers here:
variables declaration with same name C++
(5 answers)
Closed 5 years ago.
I understand that two variable can be declared of same name in two distinct function.
how can we declare a variable within a function which is already declared in the global scope?
This is called variable shadowing. In C++, you can use scope resolution operator :: to refer to global variable from inside a block. The C language does not have this, however you may use the following technique to access global variable as well:
#include <stdio.h>
int a = 100;
int main(void)
{
int a = 200;
printf("%d\n", a); // prints 200
// anonymous block used to refer to global a
{
extern int a;
printf("%d\n", a); // prints 100
}
return 0;
}
Even this is possible, be wary, that it may confuse other programmers, i.e. it violates "Don't be clever" principle.
For C++ you can always use the resolution operator to specify what scope you are talking about (::)
However in C the rule is that the variable in the context of the more specific scope is used.
int num = 5;
int main()
{
printf("%d\n", num);
int num = 3;
printf("%d\n", num);
return 0;
}
Prints
5
3
Scope of a variable is the part of he code where that variable is visible.
Therefore a global variable is visible everywhere but a local variable is visible only to a particular section of code.
#include <iostream>
using namespace std;
int a=9;
int main()
{
int a =8;
cout<<a<<endl;
cout<<::a;
return 0;
}
In the above c++ code first output is 8 whereas second is 9.
Here both variables were visible in the code but using scope resolution operator you can decide which variable you actually want.
Said in simple terms, if multiple variables in a program have the same name, then there are fixed guidelines that the compiler follows as to which variable to pick for the execution. I'll go over them all in an example below.
Global variables, as the name suggests are declared outside of any function and are accessible in any part of the code. However, in the event of another variable with the same name as the global one, the local variable would get the higher "preference" for the part of the code that comes after it is declared.
For example,
int num = 25;
class Print
{
int num;
Print();
};
Print::Print()
{
num = 98;
}
void PrintNumber(void)
{
int num = 12;
}
int main(void)
{
cout << num << endl;
int num = 34;
cout << num << endl;
PrintNumber();
Print object;
cout << object.num << endl;
}
I've tried to cover every possible scenario, please don't hesitate to inform me if I missed any scenario out. Anyways, the result of this program would be:
25
34
12
98
The first one is the global one; since the variable num of the class Print and the function PrintNumber() is localized to the object of the class and that function respectively, only the global variable is accessible here. Same for the second number, except a local variable with the same number num has a a higher privilege, so it is given a higher accessibility than the global variable (mind my erroneous English, sorry for that). Then when the PrintNumber() function is invoked, it prints the num of that local variable. Finally, an object of class Print will output the value stored in the num of that class.
Hope this answers your question.
I stumbled recently in this problem
for(int i=0,n=v.size(); i<n; i++) {
...
P2d n = ... <<<--- error here
}
the compiler was complaining about the fact that the n local variable has been already defined, despite that the open brace looks like it should start a new scope.
Indeed the standard has a special wording for this and while the code compiled fine with g++4.6.3, it complains with more recent versions and other compilers.
What is the rationale (if there is any) behind this special rule?
To be more clear: the standard explains that this is not permitted and I've no questions about the technical reason for which that's an error: I was just wondering why the committee decided to use special extra rules instead of just creating another nested scope when seeing the opening brace (like it happens in other places).
For example to make the code legal you can just wrap the body with two brace pairs instead of one...
Please also note that braces after for/while/if, while considered good practice, are not mandatory and not part of the syntax, but still a scope containing the loop variables exists (therefore using function definition as another example where the scope of the locals is the body of the function is not relevant: a function body is not a statement and braces are mandatory).
In the C++ syntax the body of a for is just a statement; however if this statement happens to be a braced group then it gets a special handling in for/while/if (that doesn't happen when you use a braced group as statement elsewhere in the language).
What is the reason for adding this extra complication to the language? It's apparently not needed and just treating the braces as another inner scope seems (to me) simpler.
Are there use cases in which this simpler and more regular approach doesn't work?
Note that I'm not asking opinions. Either you know why the committee took this decision (requiring also a quite elaborate wording in the standard instead of just having the body as a regular statement with the regular handling of a brace enclosed block when used as statement) or you don't.
EDIT
The "single scope" view for the syntax is for me unnatural but technically possible for the for statement that can be rationalized as a single block with a backward goto statement, but it's hard to defend in a very similar case for the if statement:
if (int x = whatever()) {
int x = 3; // Illegal
} else {
int x = 4; // Illegal here too
}
but this is instead legal
if (int x = whatever()) {
int z = foo();
} else {
int z = bar();
}
So are the condition, the then part and the else part of an if statement the same scope? No because you can declare two z variables. Are they separate scopes? No because you cannot declare x.
The only rationalization I can see is that the then and else part are indeed separate scopes, but with the added (strange) rule that the variable declared in the condition cannot be declared in the scope. Why this extra strange limitation rule is present is what I'm asking about.
int i = 0;
for (MyObject o1; i<10; i++) {
MyObject o2;
}
Can be translated from the point view of recent compilers into:
int i = 0;
{
MyObject o1;
Label0:
MyObject o2; //o2 will be destroyed and reconstructed 10 times, while being with the same scope as o1
i++;
if (i < 10)
goto Label0;
}
This is the answer to your last question mark at the end, they didn't add something complicated, just used goto to label in the same scope, and not goto to out of the scope and then enter to it again. I don't see clear reason why it's better. (While it will do some incompatibility with older codes)
The semantics are not special for the for loop! if (bool b = foo()) { } works the same. The odd one out is really a { } block on its own. That would be rather useless if it didn't introduce a new scope. So the apparent inconsistency is due to a misplaced generalization from an exceptional case.
[edit]
An alternative view would be to consider an hypothetical, optional keyword:
// Not a _conditional_ statement theoretically, but grammatically identical
always()
{
Foo();
}
This unifies the rules, and you wouldn't expect three scope (inside, intermediate,outside) here either.
[edit 2] (please don't make this a moving target to answer)
You wonder about lifetime and scopes (two different things) in
int i = 0;
for (MyObject o1; i<10; i++) {
MyObject o2;
}
Let's generalize that:
MyObject o2; // Outer scope
int i = 0;
for (MyObject o1; i<o1.fooCount(); i++) {
std::cout << o2.asString();
MyObject o2;
}
Clearly the call to o2.asString() refers to the outer o2, in all iterations. It's not like the inner o2 survives the loop iteration. Name lookup doesn't will use names from the outer scope when the names aren't yet defined in the inner scope - and "not yet defined" is a compile-time thing. The repeated construction and destruction of the inner o2 is a runtime thing.
Look at it this way:
A pair of braces allows you to hide variables visible inside an enclosing pair of braces (or globally):
void foo(int n)
{
// the containing block
for (int i = 0; i < n; ++i)
{
int n = 5; // allowed: n is visible inside the containing { }
int i = 5; // not allowed: i is NOT visible inside the containing { }
}
}
If you think about it this way you realize there are no special rules here.
The brackets ({}) deliminate a section of code as a block. Everything in this block is within it's own local scope:
int main(int argc, char** argv)
{
int a = 5;
std::cout<<a<<std::endl // 5
{
int a = 10;
std::cout<<a<<std::endl //10
}
std::cout<<a<<std::endl // 5
}
But wait, there is something else in that code...
int main(int argc, char** argv)
{
}
This is similar to the structure of a for loop:
for (int i = 0 ; i < 5; i++)
{
}
The function definition has code outside the {...} block too!
in this case, argc and argv are defined, and they are local to the scope of the function just like the definition of i in the above for loop.
In fact you can generalise the syntax to:
definition { expression }
Where the entirety of the above is within the scope.
In this case, the 'raw' brackets ({}) form the same structure but with an empty definition statement.
edit:
to answer your edit, in:
int i = 0;
for (MyObject o1; i<10; i++) {
MyObject o2;
}
the constructor for o2 is looped over for each loop, while the the constructor for o1 isn't.
for loop behavior goes as follows (where XXX is the current block being executed:
init
for(XXX; ; ){ }
test loop exp
for( ;XXX; ){ }
execute block
for( ; ; ){XXX}
final operation
for( ; ;XXX){ }
Back to 2.
As there is there was the c tag I would answer from that perspective. Here is an example:
#include <stdio.h>
int main(void) {
int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
for (int i = 0, n = 8; i < n; i++) {
int n = 100;
printf("%d %d\n", n, a[i]);
}
return 0;
}
It compiles without issues, see it working at ideone (C99 strict mode, 4.8.1).
C standard is clear that both scopes are considered as separate, N1570 6.8.5/p5 (emphasis mine):
An iteration statement is a block whose scope is a strict subset of
the scope of its enclosing block. The loop body is also a block whose
scope is a strict subset of the scope of the iteration statement.
There is a warning, but only with the -Wshadow option, as expected:
$ gcc -std=c99 -pedantic -Wall -Wextra -Wshadow check.c
check.c: In function ‘main’:
check.c:7: warning: declaration of ‘n’ shadows a previous local
check.c:6: warning: shadowed declaration is here
The loop control variables (i and n in this case) are considered part of the for loop.
And since they are already declared in the loop's initialization statement, most attempts (other than re-defining by using nested braces) to re-define them within the loop results in an error!
I cannot tell you why there is just one scope opened by the for loop, not a second one due to the braces. But I can say what was given back then as the reason for changing where that single scope is: Locality. Take this kind of pretty standard code:
void foo(int n) {
int s=0;
for (int i=0; i<n; ++i) {
s += global[i];
}
// ... more code ...
for (int i=0; i<n; ++i) {
global[i]--;
}
}
Under the old rules, that would have been illegal code, defining i twice in the same scope, the function. (In C back then, it was even illegal because you had to declare variables at the beginning of the block.)
That usually meant you’d leave out the declaration in the second loop – and run into problems if the code with the first loop was removed. And whatever you did, you had variables with a long time to live, which as usual makes reasoning about your code harder. (That was before everyone and their brother started to consider ten lines a long function.) Changing for to start its own scope before the variable declaration here made code much easier to maintain.
You problem is that the definition part of the for is considered inside the scope of the for.
// V one definition
for(int i=0,n=v.size(); i<n; i++) {
...
// V second definition
P2d n = ... <<<--- error here
}
I came across code similar to that below which is legal, albeit not very clever. Two stack variables in the same function in scope at the same time with the same name is legal but it can cause problems. (Read: I just wasted half an hour debugging this). At warning level 4 on VS2010 (the highest level), I would have hoped it would have caught this kind of thing. Am I missing something, or is it time to hit to whole code base with lint for a once over? Would a static analysis tool such as lint even pick up name clashes like this?
char *x = strchr(Buffer,' ');
if (x)
{
*x = 0;
x++;
char *x = strchr(x,' ')
if (x)
*x = 0;
}
PC-Lint will detect this. The following code:
main (int argc, char *argv [])
{
char *x = 0;
if (x)
{
char *x = 0;
}
}
Gives a warning:
main.cpp 6 Warning 578: Declaration of symbol 'x' hides symbol 'x' (line 3)
Edit: I didn't notice this when I wrote the original answer (below). The code you've posted is illegal, and causes undefined behavior. The offending line is this one:
char *x = strchr(x,' ');
Here the x within the strchr call does not refer to the x defined in the enclosing scope, but to the x defined previously on the same line. Hence that line reads from an uninitialized variable, which results in undefined behavior. From the C++ standard,
§3.3.2/1 [basic.scope.pdecl]
The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below. [ Example:
int x = 12;
{ int x = x; }
Here the second x is initialized with its own (indeterminate) value. —end example ]
GCC does complain if the corresponding line in the example below is changed to
int x = 21 + x; // generates "warning: x is used uninitialized in this function"
And duplicating your strchr example on VS2012 generates this warning (at /W1 and above):
warning C4700: uninitialized local variable 'x' used
Original answer follows (not entirely accurate):
There's nothing illegal about the code. You've introduced a new scope by adding braces, and you're allowed to define variables within the new scope even if those variable names have been previously defined in the enclosing scope.
All references to the variable after the new definition will refer to the local variable instead of the one in the enclosing scope, until the lifetime of the local variable ends. The following code produces no warnings on GCC even when compiled with -pedantic -Wall -Wextra
#include <iostream>
int main()
{
int x = 42;
{
std::cout << x << '\n';
int x = 21;
std::cout << x << '\n';
}
std::cout << x << '\n';
}
Output:
42
21
42
I don't know whether lint or another static analysis tool will pick out such things either. It is legal, but not advisable.