Declaring and Initializing a Variable in a Conditional or Control Statement in C++

Declaring and initializing a variable in a Conditional or Control statement in C++

It is allowed to declare a variable in the control part of a nested block, but in the case of if and while, the variable must be initialized to a numeric or boolean value that will be interpreted as the condition. It cannot be included in a more complex expression!

In the particular case you show, it doesn't seem you can find a way to comply unfortunately.

I personally think it's good practice to keep the local variables as close as possible to their actual lifetime in the code, even if that sounds shocking when you switch from C to C++ or from Pascal to C++ - we were used to see all the variables at one place. With some habit, you find it more readable, and you don't have to look elsewhere to find the declaration. Moreover, you know that it is not used before that point.


Edit:

That being said, I don't find it a good practice to mix too much in a single statement, and I think it's a shared opinion. If you affect a value to a variable, then use it in another expression, the code will be more readable and less confusing by separating both parts.

So rather than using this:

int i;
if((i = read(socket)) < 0) {
// handle error
}
else if(i > 0) {
// handle input
}
else {
return true;
}

I would prefer that:

int i = read(socket);
if(i < 0) {
// handle error
}
else if(i > 0) {
// handle input
}
else {
return true;
}

Pro/con: Initializing a variable in a conditional statement

The important thing is that a declaration in C++ is not an expression.

bool a = (CThing* pThing = GetThing()); // not legit!!

You can't do both a declaration and boolean logic in an if statement, C++ language spec specifically allows either an expression or a declaration.

if(A *a = new A)
{
// this is legit and a is scoped here
}

How can we know whether a is defined between one term and another in an expression?

if((A *a = new A) && a->test())
{
// was a really declared before a->test?
}

Bite the bullet and use an internal if. The scope rules are useful and your logic is explicit:

if (CThing* pThing = GetThing())
{
if(pThing->IsReallySomeThing())
{
}
}

How does one declare a variable inside an if () statement?

If you want specific scope for value, you can introduce a scope block.

#include <iostream>

int get_value() {
return 101;
}

int main() {
{
int value = get_value();
if(value > 100)
std::cout << "Hey!";
} //value out of scope
}

Initializing variables in an if statement

It limits the scope of length to the if alone. So you get the same benefits we originally got when we were allowed to write

for(int i = 0; i < ... ; ++i) {
// ...
}

Instead of the variable leaking

int i;
for(i = 0; i < ... ; ++i) {
// ...
}

Short lived variables are better for several reasons. But to name a couple:

  1. The shorter something lives, the less things you need to keep in mind when reading unrelated lines of code. If i doesn't exist outside the loop or if statement, then we don't need to mind its value outside of them. Nor do we need to worry its value will interact with other parts of the program that are outside of its intended scope (which may happen if i above is reused in another loop). It makes code easier to follow and reason about.

  2. If the variable holds a resource, then that resource is now held for the shortest period possible. And this is without extraneous curly braces. It's also made clear the resource is related to the if alone. Consider this as a motivating example

    if(std::lock_guard _(mtx); guarded_thing.is_ready()) {
    }

If your colleagues aren't aware of the feature, teach them! Appeasing programmers who don't wish to learn is a poor excuse to avoid features.

C++, variable declaration in 'if' expression

As of C++17 what you were trying to do is finally possible:

if (int a = Func1(), b = Func2(); a && b)
{
// Do stuff with a and b.
}

Note the use of ; of instead of , to separate the declaration and the actual condition.

what's wrong with declaring a variable inside if's condition?

You can declare a variable in the if statement in C++ but it is restricted to be used with direct initialization and it needs to convert to a Boolean value:

if (int i = f()) { ... }

C++ doesn't have anything which could be described as "declaration expression", i.e. [sub-] expressions declaring a variable.

Actually, I just looked up the clause in the standard and both forms of initialization are supported according to 6.4 [stmt.select] paragraph 1:

...
condition:
expression
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list
...

That is, it is also be possible to write:

if (int i{f()}) { ... }

Obviously, this only works in C++2011 because C++2003 doesn't have brace-initialization.

What does variable definition do in control structure in c++?

While loops expect a bool expression.

while({BOOL}) {...}

In the case of the code above

while(bool status = find(word)) {...}

simplifies down to

while(status) {...}

Status is initialized to the result of find(word) at the start of each execution of the loop.

status is then available within the loop.

§ 3.3.3 Block Scope

Names declared in the for-init-statement, the for-range-declaration, and in the condition of if, while, for,
and switch statements are local to the if, while, for, or switch statement (including the controlled
statement), and shall not be redeclared in a subsequent condition of that statement nor in the outermost
block (or, for the if statement, any of the outermost blocks) of the controlled statement;

Regarding your second question:

do not know whether variable definition "returns" a bool type to indicate the success of the definition,or variable definition returns the variable itself when used as the condition of control structure.

As long as the variable is convertible to bool, there is no issue.

Given

while(Foo x = Expression()) {...}

can be expressed as

while(static_cast<bool>(x)) {...}

as long as Foo is convertible to bool, it can be declared and used in the while conditional.

Defining variables in control structures

According to the standard, what is the difference in behavior between declaring variables in control structures versus declaring variables elsewhere? I can't seem to find any mention of it.

Declarations inside control structure introductions are no different that declarations elsewhere. That's why you can't find any differences.

6.4/3 does describe some specific semantics for this, but there are no surprises:

[n3290: 6.4/3]: A name introduced by a declaration in a condition
(either introduced by the type-specifier-seq or the declarator of the
condition) is in scope from its point of declaration until the end of
the substatements controlled by the condition. If the name is
re-declared in the outermost block of a substatement controlled by the
condition, the declaration that re-declares the name is ill-formed. [..]


Also, is there any technical reason as to why this syntax isn't given any special behavior when used in place of a conditional? For example, adding an additional set of brackets results in a compiler error; this also prevents the variable from being chained with other conditions.

An if condition can contain either a declarative statement or an expression. No expression may contain a declarative statement, so you can't mix them either.

[n3290: 6.4/1]: Selection statements choose one of several flows of control.

selection-statement:
if ( condition ) statement
if ( condition ) statement else statement
switch ( condition ) statement
condition:
expression
attribute-specifier-seq[opt] decl-specifier-seq declarator = initializer-clause
attribute-specifier-seq[opt] decl-specifier-seq declarator braced-init-list

It all just follows from the grammar productions.

When was the ability to declare a variable in the if statement introduced in C++?

The first formal C++ Standard was ISO/IEC 14882:1998 (a.k.a. C++98). In this 'draft' version of that, the declaration of a variable inside an if statement is explicitly mentioned:

6.4 Selection statements       [stmt.select]




3     A name
introduced by a declaration in a condition (either introduced by the
type-specifier-seq or the declarator of the condition) is in scope
from its point of declaration until the end of the substatements
controlled by the condition. If the name is re-declared in the
outermost block of a substatement controlled by the condition, the
declaration that re-declares the name is ill-formed. [Example:

if (int x = f()) {
int x; // ill-formed, redeclaration of x
} else {
int x; // ill-formed, redeclaration of x
}

—end example]

So, in terms of formal Standards: Yes, it's "been there since the beginning."

What is the result of an initialization in C++?

A declaration statement with an initializer is a just a declaration statement, not an expression. It does not yield a value. You can't do something like int x = (int n = 42);.

The while loop is something of a special case. You can use a declaration as the condition of a while loop. According to cppreference.com,

If this is a declaration, the initializer is evaluated before each
iteration, and if the value of the declared variable converts to
false, the loop is exited.



Related Topics



Leave a reply



Submit