38

Let's say I have a class defined as follows:

class foo{};

now, this is perfectly acceptable;

foo f;

how come this is a compiler error? (uninitialized const ‘f’)

const foo f;

Why do we have to do this?

const foo f = foo();

I know why we can't do this..

const foo f(); // though it compiles..

Interestingly, the following is valid:

const std::string f;

So what is missing from foo?

I realize that there are three questions there and it's bad form, but I'm hoping someone can clear this up for me in one answer.

EDIT: please feel free to close it if it's stupid...

Nim
  • 33,299
  • 2
  • 62
  • 101
  • 6
    By the way, I have seen many stupid questions on Stack Overflow. Yours is *not* a stupid question by any means. – Konrad Rudolph Jan 12 '11 at 21:54
  • @Konrad Rudolph, I was sitting there scratching my head, and normally when that happens to me, it's inevitably because I've done something stupid... :) – Nim Jan 12 '11 at 22:05

4 Answers4

48

Your class is a POD (essentially because it doesn’t provide a default constructor). POD variables are not initialized upon declaration. That is, this:

foo x;

does not initialize x to a meaningful value. This has to be done separately. Now, when you declare it as const, this may never happen because you cannot assign to or change x any more.

Consider the equivalence to int:

int x; // legal
const int y; // illegal

As you have noticed, using std::string instead of foo compiles. That’s because std::string is not a POD. A simple solution to your dilemma is to provide a default constructor for foo:

class foo {
public:
    foo() { }
};

Now your const foo x; code compiles.

Community
  • 1
  • 1
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • @Konrad what's really interesting is that gcc is the only one that gives an error. When I tried this with other compilers like msvc, CodeGear, and digital mars they all compiled with no complaints. Is this behavior non-standards compliant? – greatwolf Jan 12 '11 at 22:00
  • @Victor: did you really make sure that the `foo` class was a POD (i.e. by having no members at all)? If so, then yes, those compilers are non standards compilant. This code shouldn’t compile. – Konrad Rudolph Jan 12 '11 at 22:04
  • @Konrad yes, foo is just an empty struct. I had one version with and without a default constructor. I just tested this with comeau and it correctly catches this too. So it looks like only gcc and comeau are in compliance. – greatwolf Jan 12 '11 at 22:12
  • @Nim: neither did I realize it either, if that's any consolation, guess I have not done enough C... – Matthieu M. Jan 13 '11 at 07:21
  • @Victor T: Did you check the compilation flags ? MSVC is reknown for its extensions to the standard, and it may simply initialize the struct as if it were a non-POD. I can't recall the equivalent of `-pedantic` for it, but perhaps should you test that ? – Matthieu M. Jan 13 '11 at 07:23
6

Raising an error in the situation of an empty class is a known problem, and reported as issue #253.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
1

const, applied to a simple plain-old-data variable, indicates that that variable will not change in that context - so you aren't going to be able to reassign it to something. Therefore, you must initialize it or it will be perpetually uninitialized and thus useless.

  • "_applied to a simple plain-old-data variable, indicates that that variable will not change in that context_" and with a non-POD, it means less? ;) [Hint: it doesn't] – curiousguy Dec 11 '11 at 21:43
1

I think there are more alternatives. You can do

const foo f={};

or

const foo f(());

Const means you can not assign to it later, so you have to initialize it. Since you did not define default constructor the compiler assumes it has to be initialized by you. std::string has default constructor so it is called implicitly by compiler.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Öö Tiib
  • 10,809
  • 25
  • 44
  • But the two forms are not equivalent in general: the first form will initialise all members of `foo` to 0 (suitably converted), the second form will value-initialise `f`: it will call the default constructor if there is one, either it will value-initialise every member: call the default constructor for the member, if there is one, or value-initialise every member of the aggregate, if it is an aggregate, or initialise the member to 0 (suitably converted). – curiousguy Dec 11 '11 at 21:54
  • “`const foo f(());`” is not valid syntax – gx_ Dec 18 '13 at 15:34