5

The compiler throws no warnings or errors for the following code. Is the meaning of the const qualifier being abused? Obviously I cannot reassign it later in the same loop iteration but it does seem to reassign it after each iteration.

Sample code:

for(int i = 0; i < 10; ++i)
{
  const int constant = i;
}
curiousguy
  • 8,038
  • 2
  • 40
  • 58
user393454
  • 139
  • 1
  • 7
  • 6
    Question: what is the lifetime of `constant` here? – Tristan Brindle Jul 27 '17 at 17:40
  • 4
    Each time around the loop a new `constant` is created and destroyed. You are not re-initializing anything. – Jesper Juhl Jul 27 '17 at 17:41
  • You should get a warning about that not being used, but perhaps you haven't turned on all the right warnings. – tadman Jul 27 '17 at 17:42
  • 3
    C++ doesn't define the concept of reinitialization. Intuitively, reinitialization implies an object that has already been initialized. However, [initialization](http://en.cppreference.com/w/cpp/language/initialization) can only happen at the creation of an object. It means to provide an object with it's state or value at the time of construction. An object that already exists can't be initialized. The closest thing would be to assign it a new value. – François Andrieux Jul 27 '17 at 17:51
  • C and C++ are different languages. Remove the unrelated tag. – too honest for this site Jul 27 '17 at 17:56
  • @Olaf Does the code behave differently in each language? – user393454 Jul 27 '17 at 18:02
  • @user393454: That's what "different languages" implies. The semantics of this snippet are indeed different. As you asked about a C++ primer, I removed the C tag. And yes, you should learn the language by a good book, not by obscure youtube videos, blogs or trial&error. – too honest for this site Jul 27 '17 at 18:04
  • 1
    @user393454 while *this code* may not behave differently when being compiled as either C or C++, there are *plenty* of examples of code that are syntactically valid in both languages but have different semantics. Thus, it is important to be precise when tagging what language you are using. – Jesper Juhl Jul 27 '17 at 18:06
  • @Olaf If you are correct about the semantics being different then I agree, but now I'm curious as to how the semantics differ, as Jesper Juhl seems to disagree. – user393454 Jul 27 '17 at 18:11
  • 1
    I don't see @JesperJuhl disagrees. Read his comment carefully. About the details: Please understand we are not a tutoring site, less in comments. You will find all information in the two standards and a lot already by some research on your own. – too honest for this site Jul 27 '17 at 18:17
  • @Olaf I believe you are missing the conversational implicature in Jesper Juhl's comment unless you are drawing a distinction between semantics and behavior. But most importantly, I don't see how asking for support for the claim "the semantics of this snippet are indeed different" is considered tutoring unless support for claims is not expected in comments. I do not intend to be irksome with this comment. – user393454 Jul 27 '17 at 18:39
  • @user393454: 1) No, I don't. There definitively is a difference between semantics and behaviour! Otherwise two different languages could not both be turing-complete, e.g. 2) "but now I'm curious as to how the semantics differ" - I understood this as asking to elaborate, which would be too broad and go into the direction of tutoring. If I missunderstood you, please excuse me. – too honest for this site Jul 27 '17 at 18:47
  • @Olaf I believe this would be better resolved in a chat room, if you'd like to start one. If not: 1) No you don't believe you missed the implicature? I was not saying that there was not a distinction. I was trying to find how you were reading Jesper Juhl's comment. 2) I do not see why you would make a claim that was too broad to support concisely, and furthermore it is difficult to believe that you cannot provide a difference in semantics for such a small snippet, given that you claim there is one. 3) What is your definition of semantics as a c++ programmer? Does it involve proofs? – user393454 Jul 27 '17 at 19:34
  • 2
    Tip: Use C and C++ together with caution - it is a DV magnet - fair or not. Most of the time, only one should be used. Many times even though the post's problem exists in both, the solution differs. For the select posts that use both tags and both tags make sense, be sure to provide justification details to avoid grief. – chux - Reinstate Monica Jul 27 '17 at 20:55
  • @Olaf "_C and C++ are different languages_" with a very important common subset – curiousguy Aug 16 '17 at 18:41
  • "_There definitively is a difference between semantics and behaviour!_" what are you trying to say? – curiousguy Aug 16 '17 at 18:42

4 Answers4

10

You aren't re-initializing it, you're just initializing it in each loop iteration*. Formally there is a new int being created and destroyed in each loop iteration, although the compiler can do whatever it wants as long as it seems to behave that way.


* You can't really "re-initialize" things in C++, initialization only happens once in the lifetime of an object

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Is there a good primer on C++ variable scope? That seems to be a fundamental misunderstanding that lead to this question being asked. – tadman Jul 27 '17 at 17:41
  • Is initializing a constant in a loop considered bad practice? – user393454 Jul 27 '17 at 17:43
  • @user393454 It depends on *why* you're initializing it. This example doesn't do anything useful, so it's a bad practice because it's pointless. In other situations it might make sense. – tadman Jul 27 '17 at 17:45
  • @user393454 any optimizing compiler worth its salt will either hoist it out of the loop if it is truely constant and initialized to the same value on every loop iteration or just remove the temporary variable if it depends on the loop but always has the same value as something else. So it really doesn't matter (although I'm sure you *could* come up with some contrived case that fools the optimizer - but that's most likely irrelevant for real code). – Jesper Juhl Jul 27 '17 at 17:48
  • @tadman fair enough, but say it's a const reference that I pass to a function in the loop. then the const qualifier is useful, so the initialization of a const reference on every iteration is warranted, right? – user393454 Jul 27 '17 at 17:53
  • @user393454 The compiler can easily convert non-`const` to `const` when calling a function, so that might not be necessary. – tadman Jul 27 '17 at 17:54
  • @tadman that's not the case I was considering. If I want to ensure that the function is not modifying the value of the variable, I qualify the variable with const. While this may not be useful to the compiler, it is useful to the programmer. – user393454 Jul 27 '17 at 18:00
  • @user393454 while `const` is useful to the programmer to prevent errors, it is useless to the optimizer - the reasons being that `const_cast` (including C-style casts) exist in the language, `mutable` existing in the language, pointers/references potentially aliasing, etc. `const` is nice, it prevents errors, but its useful only to the programmer, *not* the optimizing compiler. – Jesper Juhl Jul 27 '17 at 18:03
  • @user393454 Up to you then. It depends on how little you trust your fellow devs. – tadman Jul 27 '17 at 18:05
  • @JesperJuhl: That is _partly_ correct in C (a modern toolchain might surprise you, too), but not in C++. A modern compiler will very well use that knowledge. If you cast inappropriately, e.g. un-qualify an object, i.e. invoking UB, you are on your own anyway. – too honest for this site Jul 27 '17 at 21:17
8

If to follow the C Standard then (6.2.4 Storage durations of objects)

1 An object has a storage duration that determines its lifetime. There are four storage durations: static, thread, automatic, and allocated. Allocated storage is described in 7.22.3.

and

5 An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration, as do some compound literals. The result of attempting to indirectly access an object with automatic storage duration from a thread other than the one with which the object is associated is implementation-defined.

6 For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration or compound literal is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached

And at last (6.8.5 Iteration statements)

5 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.

Thus in this loop statement

for(int i = 0; i < 10; ++i)
{
    const int constant = i;
}

the body of the loop is a block. The variable constant has the automatic storage duration. A new instance of the variable is created each time the block is executed recursively.

In C++ you may add storage class specifier static. In this case the variable indeed will be initialized only once because it has the static storage duration ( In C you may not do the same because the variable must be initialized by a constant expression).

Here is a demonstrative program

#include <iostream>

int main() 
{
    for ( int i = 0; i < 10; ++i )
    {
        static const int constant = i;
        std::cout << "constant = " << constant << std::endl; 
    }

    return 0;
}

Its output is

constant = 0
constant = 0
constant = 0
constant = 0
constant = 0
constant = 0
constant = 0
constant = 0
constant = 0
constant = 0
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

You're not actually reinitializing here. You're creating a new variable each time through the loop.

constant is local to the block inside of the loop. When the block finishes on a given iteration and control goes back to the for, constant goes out of scope and therefore no longer exists. When the for starts the next iteration of the loop, a new instance of constant is created and initialized.

dbush
  • 205,898
  • 23
  • 218
  • 273
1

This variable gets initialized and destroyed on each iteration because it's local to the loop.

ForceBru
  • 43,482
  • 10
  • 63
  • 98