5

If a const variable which has been assigned can still be reassigned, then it's not a const? Take for instance:

 struct ss
 {
     const int m = 1024;

     ss()
     {
     }

     ss(int m) : m(m)
     {
     }
 };



ss sa;
ss sb(-1);

cout << sa.m << endl;
cout << sb.m << endl; 

Wow m is not constant after all!

> /* Ouput:
> 
> 1024
> -1
> 
> */
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
user3613229
  • 101
  • 4
  • 1
    Reassigned? You never reassign it. – chris Jun 15 '14 at 02:35
  • 3
    Related to [Has the new C++11 member initialization feature at declaration made initialization lists obsolete?](http://stackoverflow.com/questions/24149924/has-the-new-c11-member-initialization-feature-at-declaration-made-initializati/24150137#24150137). – Shafik Yaghmour Jun 15 '14 at 02:36
  • 8
    There is no assignment or reassignment in this code. There is only initialisation, which happens exactly once for each variable. – n. m. could be an AI Jun 15 '14 at 02:38
  • 3
    It certainly seems an unintuitive trap for the unwary that constructor initializer lists take precedence over initialization at declaration. – Matt Coubrough Jun 15 '14 at 02:52

2 Answers2

11
 ss(int m) : m(m)
 {
 }

This says that when the class ss is initialized, its member m is initialized using the parameter m. The member m indeed cannot be modified, but it can be initialized, just like any other const object. Note that if we did instead

 ss(int m)
 {
     this->m = m;
 }

then we would have a problem, as ss::m needs to be initialized. And if ss::m were a class with a default constructor, then in

 ss(FooClass m)
 {
     this->m = m;
 }

it's OK to not initialize ss::m explicitly (as it will just be default-constructed), but the line in the body of the constructor would be rejected as it would modify ss::m after it has already been initialized.

Edit: Whoops, I didn't understand your original question.

A brace-or-equal-initializer such as

const int m = 1024;

is only used if the member is not mentioned in the ctor-initializer. In other words, since the default constructor doesn't explicitly initialize m, the value 1024 is used. But ss::ss(int) does explicitly initialize m, so the brace-or-equal-initializer is ignored.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • 3
    You didn't address the `const int m = 1024;` line, which is the crux of the issue. – user2357112 Jun 15 '14 at 02:36
  • +1 but you got the terminology wrong at the end. *mem-initializer* is the initializer in the constructor initializer list. The non-static data member initializer is the *brace-or-equal-initializer*. – Praetorian Jun 15 '14 at 04:11
5

Your example just deals with different modes of initialization, no reassignment is happening here. What you are seeing is the effect of the constructors initializer list being preferred over the in class member initializer, we can see from the draft C++ standard section 12.6.2 Initializing bases and members paragraph 9 which says:

If a given non-static data member has both a brace-or-equal-initializer and a mem-initializer, the initialization specified by the mem-initializer is performed, and the non-static data member’s brace-or-equal-initializer is ignored. [ Example: Given

struct A {
int i = / some integer expression with side effects / ;
A(int arg) : i(arg) { }
// ...
};

the A(int) constructor will simply initialize i to the value of arg, and the side effects in i’s brace-orequal- initializer will not take place. —end example ]

As discussed in Has the new C++11 member initialization feature at declaration made initialization lists obsolete? this is a useful features since it allows you to default member variables and then override those defaults based on the constructor that is called.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740