2

Rather surprised to find this question not asked before. Actually, it has been asked before but the questions are VERY DIFFERENT to mine. They are too complicated and absurd while I'll keep it simple and to the point. That is why this question warrants to be posted.

Now, when I do this,

struct A {
    int a = -1;
};

I get the following error: ANSI C++ forbids in-class initialization of non-const static member a

Now, along with the workaround can someone please tell me THE BEST way of initializing a struct member variable with a default value?

  • 3
    If you are asking about C++ prior to C++11, then indeed your code doesn't compile. – didierc Feb 14 '15 at 19:04
  • 3
    Do we really need the shouting and the self-gratification in this question? Just ask how to default-initialize a struct. And then consider _reading_ the existing questions on the topic instead of waving them away as being "absurd". – Lightness Races in Orbit Feb 14 '15 at 19:49
  • 1
    You do it just the way you wrote. Just update your compiler to a more recent version. – sp2danny Feb 14 '15 at 23:12

2 Answers2

5

First, let's look at the error:

ANSI C++ forbids in-class initialization of non-const static member a

Initialization of a true instance member, which resides within the memory of an instance of your struct is the responsibility of this struct's constructor.

A static member, though defined inside the definition of a particular class/struct type, does not actually reside as a member of any instances of this particular type. Hence, it's not subject to explaining which value to assign it in a constructor body. It makes sense, we don't need any instances of this type for the static member to be well-initialized.

Normally, people write member initialization in the constructor like this:

struct SomeType
{
    int i;
    SomeType()
    {
        i = 1;
    }
}

But this is actually not initialization, but assignment. By the time you enter the body of the constructor, what you've done is default-initialize members. In the case of a fundamental type like an int, "default-initialization" basically boils down to "eh, just use whatever value was in those bytes I gave you."

What happens next is that you ask i to now adopt the value 1 via the assignment operator. For a trivial class like this, the difference is imperceptible. But when you have const members (which obviously cannot be tramped over with a new value by the time they are built), and more complex members which cannot be default-initialized (because they don't make available a visible constructor with zero parameters), you'll soon discover you cannot get the code to compile.

The correct way is:

struct SomeType
{
    int i;
    SomeType() : i(1)
    {
    }
}

This way you get members to be initialized rather than assigned to. You can initialize more than one by comma-separating them. One word of caution, they're initialized in the order of declaration inside your struct, not how you order them in this expression.

Sometimes you may see members initialized with braces (something like i{1} rather i(c)). The differences can be subtle, most of the time it's the same, and current revisions of the Standard are trying to smooth out some wrinkles. But that is all outside the scope of this question.

Update: Bear in mind that what you're attempting to write is now valid C++ code, and has been since ratification of C++11. The feature is called "Non-static data member initializers", and I suspect you're using some version of Visual Studio, which still lists support as "Partial" for this particular feature. Think of it as a short-hand form of the member initialization syntax I described before, automatically inserted in any constructor you declare for this particular type.

ZaldronGG
  • 924
  • 8
  • 13
  • 1
    `i{1}` was added in C++11 – M.M Feb 14 '15 at 22:30
  • True, I almost wrote {} there, personally I'm in the field of auto'ing and brace-initializating everything, but I felt that would muddy up the answer. – ZaldronGG Feb 14 '15 at 22:47
  • 1
    You should explain that OP's code is valid C++. They just don't have a compiler that supports the latest standards. – juanchopanza Feb 14 '15 at 22:47
  • Duly noted, updated the answer. I forgot this was now valid, for a minute there I thought I only used this in C# :) – ZaldronGG Feb 14 '15 at 22:56
0

You could make a default constructor

struct A {
    A() : a{-1} {}
    int a;
};
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • Looks different to a conventional constructor. What's up with that? – The Vigilante Sting Feb 14 '15 at 18:58
  • 1
    It is using a [member initialization list](http://en.cppreference.com/w/cpp/language/initializer_list) instead of initializing in the constructor body. This is [preferable in general](https://stackoverflow.com/questions/4589237/in-this-specific-case-is-there-a-difference-between-using-a-member-initializer) particularly if member variables are classes. – Cory Kramer Feb 14 '15 at 19:00
  • Hmmm... I wish there was a standard convention followed everywhere. – The Vigilante Sting Feb 14 '15 at 19:02
  • This is the type of thing that would be covered by a company's style guide instead of the C++ standard. For example here is [Google's C++ Style Guide](https://google-styleguide.googlecode.com/svn/trunk/cppguide.html). The way I wrote the constructor is very common and widely accepted. – Cory Kramer Feb 14 '15 at 19:06
  • You should at the very least explain that OP's code is valid C++. – juanchopanza Feb 14 '15 at 19:20
  • 1
    @TheVigilanteSting: This _is_ a conventional constructor, and it's absolutely standard convention. – Lightness Races in Orbit Feb 14 '15 at 19:50
  • 2
    `a{-1}` is invalid in C++03. (If OP can use C++11 then no workaround is necessary, and there's a very good case to argue that OP's technique is the best one) – M.M Feb 14 '15 at 22:29