8

I am trying to learn how to use constant functions and objects, however, I have some error that has kept me up for over an hour and I can't seem to figure out. I was following a simple example and I guess I got lost somewhere along the way. Here is my code.

Main.cpp

#include <iostream>
#include "ExampleClass.h"

int main(){
    ExampleClass exampleObj; // object used to call members of ExampleClass.
    exampleObj.printText(); // calls printVar from the ExampleClass.

    const ExampleClass constantObject; // object used to call constant members of ExampleClass.
    constantObject.printConstText(); // calls printConstVar from the ExampleClass.

    return 0;
}

ExampleClass.h

#ifndef EXAMPLECLASS_H
#define EXAMPLECLASS_H


class ExampleClass
{
    public:
        void printText();
        void printConstText() const;
};

#endif // EXAMPLECLASS_H

ExampleClass.cpp

#include <iostream>
#include "ExampleClass.h"

void ExampleClass::printText(){
    std::cout << "The code works!" << "\n";
}

void ExampleClass::printConstText() const{
    std::cout << "The code works!" << "\n";
}

And I'm getting the error:

C:\Documents and Settings\Me\My Documents\ConstObjects\main.cpp||In function 'int main()':|
C:\Documents and Settings\Me\My Documents\ConstObjects\main.cpp|8|error: uninitialized const 'constantObject'|
||=== Build finished: 1 errors, 0 warnings ===|

If I take out the const before ExampleClass the code executes fine. But is it still a constant object? Thanks for the help, I hope I gave enough information. If it matters at all I'm using Code Blocks.

  • 1
    In case you're misunderstanding, you don't need a constant object to call constant member functions. The relationship is that a constant object can **only** call constant member functions. – chris Aug 15 '12 at 06:58
  • 3
    Just a note: You don't need both `printText` and `printConstText`, the `const` method qualifier will make the functions different even if they are named the same. – Some programmer dude Aug 15 '12 at 06:59
  • 2
    The code looks fine, what compiler are you using? Is the code shown really the code, that produces the error message? No &-sign? – Torsten Robitzki Aug 15 '12 at 07:00
  • @TorstenRobitzki No, the code isn't fine. The error message is correct. A `const` object must be initialised. –  Aug 15 '12 at 07:01
  • I know. But, I am trying to learn how to use constant objects. Is it even worth learning if regular objects can call constant functions anyway? –  Aug 15 '12 at 07:01
  • And yes this is the code that produces the error. I copied it from CodeBlocks and pasted it piece by piece on the question. I copied and pasted the error message too. –  Aug 15 '12 at 07:03
  • 1
    @hvd, I am not sure that the error messasge is relevant. This object does not have data members. What should be inited?? – Kirill Kobelev Aug 15 '12 at 07:03
  • @LwinHtooKo VC++6 is by no means a standards-conforming C++ compiler. –  Aug 15 '12 at 07:04
  • @hvd How do I initialize a const object? That's what I'm trying to do. –  Aug 15 '12 at 07:04
  • @hvd Every object must be initialized, that's not only true for const objects. – Torsten Robitzki Aug 15 '12 at 07:05
  • @KirillKobelev The class itself. `= {}` should also work without adding a constructor. –  Aug 15 '12 at 07:05
  • @TorstenRobitzki `int a; a = 3;` is perfectly valid. `a` is never initialised, it's only assigned to. –  Aug 15 '12 at 07:05
  • For the record, it compiles fine with GCC 4.6.3 and a 4.8 snapshot. – juanchopanza Aug 15 '12 at 07:07
  • @hvd, `= {}` is neither wise, nor reasonable. Event if this stated in the standard (?). – Kirill Kobelev Aug 15 '12 at 07:10
  • I don't have more recent than 4.5.3 installed here, but that produces the error. Is it possible that C++11 changed the rules and that GCC uses the new rules even in C++98 mode? –  Aug 15 '12 at 07:10
  • @KirillKobelev What's unwise or unreasonable about it? Anyway, you need that unless you add a constructor. –  Aug 15 '12 at 07:11
  • This is a default ctor that is automatically generated in many other cases. How putting an empty braces will help? – Kirill Kobelev Aug 15 '12 at 07:13
  • @KirillKobelev Without the empty braces, no constructor will get called. –  Aug 15 '12 at 07:14
  • @hwd, and what? Why implicit ctor can be successfuly called in all other places but not here? What is special? You need to give **reasons**, not just state something that has no base under it. – Kirill Kobelev Aug 15 '12 at 07:17
  • 1
    @hvd: Yes the rules did change in C++11. – CB Bailey Aug 15 '12 at 07:18
  • @KirillKobelev The reasons have already been stated by others, so I didn't feel a need to repeat it. Basically, the (old) standard says a POD class with an implicit constructor doesn't get initialised unless you initialise it. That's why explicitly creating a constructor also works. –  Aug 15 '12 at 07:21
  • @CharlesBailey Thanks, in that case, I will take a look at the new rules when I get the chance. –  Aug 15 '12 at 07:21
  • @hvd. Reason == no reason. Great! – Kirill Kobelev Aug 15 '12 at 07:24
  • 1
    possible duplicate of [declaring a const instance of a class](http://stackoverflow.com/questions/4674332/declaring-a-const-instance-of-a-class) – juanchopanza Aug 15 '12 at 07:28
  • @KirillKobelev The reason why the compiler behaves like that is nothing more than "because the standard says it must". Are you instead asking why the standard is written the way it is? –  Aug 15 '12 at 07:28
  • @hvd. First, I do not see any references to the stnd above. Second, even standard has gaps and unreasonable statements. Once the standards has a problem (ex: export with templates in C++03), it is necessary to admit that rather than continue saying that everything is right there and does not need reasons. Even standard needs reasons. – Kirill Kobelev Aug 15 '12 at 07:33
  • 1
    @hvd I guess [this issue](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253) got dealt with in C++11. In any case, with GCC 4.6.3 the code compiles with and without C++11 support. – juanchopanza Aug 15 '12 at 07:33
  • @KirillKobelev This comment area is rather limited. Which part would you like? That const objects must be initialised? That POD classes aren't initialised unless you initialise them? That the class in this question is a POD class? And you don't explain why any of this is unreasonable, so I have trouble taking that seriously. –  Aug 15 '12 at 07:38
  • @juanchopanza It's still listed as "drafting", so it's probably not (completely) resolved in C++11, but Charles Bailey did say the rules changed in C++11, so I'm guessing it's partially resolved? –  Aug 15 '12 at 07:40
  • @hvd: The requirement for a non-POD class type to have a user-declared constructor if a const-qualified object doesn't have an initializer has been removed as has the requirement for const-qualified objects of POD-class type to have an initializer. – CB Bailey Aug 15 '12 at 07:50

3 Answers3

6

The const object "constantObject" needs an initializer or requires "class ExampleClass" to have a user-declared default constructor.

Lwin Htoo Ko
  • 2,326
  • 4
  • 26
  • 38
  • 2
    Doesn't the compiler generate a default constructor? – Luchian Grigore Aug 15 '12 at 07:01
  • No, by all means! The compiler generates a default constructor for you. Please do not add any code that is pointless and unnecessary it makes code so hard to read. – Torsten Robitzki Aug 15 '12 at 07:02
  • If an object of const type is defined without initializer, a *user-declared* default constructor is required. – AnT stands with Russia Aug 15 '12 at 07:03
  • 1
    @Luchian Grigore: The compiler does generate a default constructor. But in this case language requires a default constructor explicitly declared by the user. – AnT stands with Russia Aug 15 '12 at 07:04
  • @AndreyT it's not *required*. You can initialize the object without a default constructor – Luchian Grigore Aug 15 '12 at 07:05
  • @Luchian Grigore: You can. However, again, if (as in this case) you define a const object without initializer, the class must have user-declared default constructor. This is a quote straight from the standard. When I say "in this case" I refer to OP's code, in which the const object is defined *without* an initializer. – AnT stands with Russia Aug 15 '12 at 07:06
  • It doesn't need a default constructor, you can explicitly initialize constant object: `const ExampleClass = {};` – CB Bailey Aug 15 '12 at 07:07
  • @CharlesBailey agreed. This answer is misleading. – Luchian Grigore Aug 15 '12 at 07:08
  • And yes. CodeBlocks creates a constructor upon creation of the class, but I must have deleted it when I was trying to get rid of an old function or something. I didn't realize that I needed the constructor though. –  Aug 15 '12 at 07:12
  • The const object "constantObject" needs an initializer or requires to have a user-declared default constructor. – Lwin Htoo Ko Aug 15 '12 at 07:12
5

Your ExampleClass is a POD (plain old data) structure. When it's declared as a local variable like this ExampleClass exampleObj no default constructor gets called and it remains uninitialized.

You need either to create a default constructor of your own or use the following syntax -ExampleClass exampleObj = ExampleClass();. This will create a temporary ExampleClass object and value initialize your exampoleObj.

updated:

Here is an excerpt from C++03 standard 8.5.9.

If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized;

if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor. [this one applies to const objects]

Otherwise, if no initializer is specified for a nonstatic object, the object and its subobjects, if any, have an indeterminate initial value); if the object or any of its subobjects are of const-qualified type, the program is ill-formed. [this one applies to const and POD types]

This means that the constantObject should have user-defined default constructor, otherwise a program is ill-formed, which should be diagnosed. If we remove const, the object will remain uninitialized anyway (will have indeterminate initial value)

Community
  • 1
  • 1
Maksim Skurydzin
  • 10,301
  • 8
  • 40
  • 53
  • OP said his code works if he makes the object non-const. So does a default constructor get called in that case? – Moritz Aug 15 '12 at 07:03
  • 1
    @Luchian Grigore: Not true. If the definition has no initializer, default constructor is called for non-POD class types only. For POD class types (as in this example) the object is simply left uninitialized. The `()` syntax does not call constructor either. – AnT stands with Russia Aug 15 '12 at 07:12
  • @AndreyT I don't see a contradiction. The compiler generated default constructor can leave members uninitialized. – Luchian Grigore Aug 15 '12 at 07:14
  • @Luchian Grigore: That's correct. However, the standard is very specific about it: constructor is called for non-POD classes only. The rationale is probably to leave the path open for *value-initialization* (instead of constructor call) in response to `()` initializer. For a POD type the `()` does not call constructor, but instead performs *value-initialization*, which is a completely different initialization mechanism. – AnT stands with Russia Aug 15 '12 at 07:15
  • @AndreyT: True in C++03; not true in C++11. In C++11 such values are default-initialized which changed meaning in C++11 to mean calling the default constructor which does no initialization. The effect is the same but technically, in C++11, the compiler generated default constructor is called to do no initialization rather than no initialization taking place. – CB Bailey Aug 15 '12 at 07:17
1

This behaviour is considered and issue and seems to have been fixed, at least in newer versions of GCC, and presumably in the C++11 standard. See here for the issue report.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480