Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does C++ not have a const constructor?

(Edit: Heavy change because previous example was flawed, which may make some answers/comments seem odd)

This might be an overly contrived, but the following is legal because of lack of const constructor:

class Cheater { public:     Cheater(int avalue)         : cheaterPtr(this) //conceptually odd legality in const Cheater ctor        , value(avalue)      {}      Cheater& getCheaterPtr() const {return *cheaterPtr;}     int value;  private:     Cheater * cheaterPtr; };  int main() {     const Cheater cheater(7); //Initialize the value to 7      cheater.value                 = 4;    //good, illegal     cheater.getCheaterPtr().value = 4;    //oops, legal      return 0; } 

It seems like providing a const constructor a thing would be as easy technically as const methods, and be analogous to a const overload.

Note: I'm not looking for 'Image( const Data & data ) const' but rather 'const Image( const Data & data) const'

So:

  • Why is the const constructor absent in C++?

Here's some related material for context:

  • http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1995/N0798.htm
  • How to deal with initialization of non-const reference member in const object?
  • C++, Classes, Const, and strange syntax
like image 873
Catskul Avatar asked Aug 04 '11 04:08

Catskul


People also ask

Can a constructor be const?

Constructors may be declared as inline , explicit , friend , or constexpr . A constructor can initialize an object that has been declared as const , volatile or const volatile . The object becomes const after the constructor completes.

Can we make constructor constant in C++?

Constructors and destructors can never be declared to be const . They are always allowed to modify an object even if the object itself is constant.

Is const same as constructor?

That is: A const constructor can also be used as a normal constructor to create objects at runtime, as well as creating compile-time constant objects at compilation time.

Why does copy constructor have const?

When we create our own copy constructor, we pass an object by reference and we generally pass it as a const reference. One reason for passing const reference is, we should use const in C++ wherever possible so that objects are not accidentally modified.


2 Answers

Just because Image is const in your imaginary constructor doesn't mean that what m_data points to is. You'd end up being able to assign a "pointer to const" to a "const pointer to non-const" inside your class, which would remove constness without a cast. This would obviously allow you to violate invariants and couldn't be allowed.

As far as I know, any specific sets of const-ness that are needed can be accurately and completely specified within the current standard.

Another way to look at it is that const means the method doesn't mutate your object's state. A constructor's sole purpose is to initialize an object's state to be valid (well hopefully anyway - any constructors with side effects should be ...carefully evaluated).

EDIT: In C++ constness applies to both members, and for pointers and references, to the accessible constness of the referred object. C++ consciously made the decision to split out these two different const-nesses. Firstly, do we agree that this code demonstrating the difference should compile and print out "non-const"?

#include <iostream>  struct Data {     void non_const() { std::cout << "non-const" << std::endl; } };  struct Image {      Image(             Data & data ) : m_data( data ) {}       void check() const { m_data.non_const(); }      Data & m_data; };  int main() {     Data data;     const Image img(data);     img.check();      return 0; } 

So then in order to obtain the behavior where it could accept a const-ref and store it as const-ref, the effective declaration of the reference would have to change to be const. This would then mean that it would be a completely distinct type, NOT a const version of the original type (since two types with members differing in const-qualification are treated as two separate types in C++). Thus, either the compiler has to be able to do excessive behind-the-scenes magic to convert these things back and forth, remembering the const-ness of the members, or it has to treat it as a separate type which then couldn't be used in place of the normal type.

I think what you're trying to achieve is a referencee_const object, a concept that only exists in C++ as a separate class (which I suspect could be implemented with judicious use of templates although I didn't make an attempt).

Is this strictly a theoretical question (answer: C++ decided to split object and referencee constness) or is there an actual practical uncontrived problem you're trying to solve?

like image 54
Mark B Avatar answered Oct 14 '22 20:10

Mark B


It would not be a const method itself

If this constructor were not a const method itself, then the internal pointers and such would also not be const. Therefore, it could not set const values into those non-const members.

The only way to make it work syntactically is for this constructor to require member initialization for all non-mutable members. Essentially, any member not declared mutable would be implicitly declared const when using this constructor. Which is equivalent to making the constructor a const method; only initializers could initialize members. The constructor's body could do nothing with non-mutable members, because those members would be const at that point.

What you are asking for is syntactically dubious. You're essentially trying to hoodwink the API, storing constant data in an object that is designed for mutable data (which is why you didn't declare the member pointer to be const). If you want different behavior for an object, you need to declare the object to have that specific behavior.

like image 26
Nicol Bolas Avatar answered Oct 14 '22 22:10

Nicol Bolas