0

I am with doubt regarding clean code/coding style, the doubt is, when should I use the keyword const in C++ constructor parameters. For example, consider the following class:

class A {
    public:
    B& b;
    explicit A (const B& b_): b(b_) {}
    };

In this code, I want to initialize the reference b from the class A, and at the same time, I want to express that the reference passed as a parameter to the class A constructor will not be used to change the values of the object b_. However, the presented code will not compile, and the compiler will present the message:

"error: binding reference of type ‘B&’ to ‘const B’ discards qualifiers"

I know I can use the keyword const in the b class attribute, however, it will make the attribute constant, and I do not want to impose this constraint over the attribute. So, I would like to know what should I do in this situation.

  • Use `const` whenever possible. – Jesper Juhl Jan 24 '20 at 20:01
  • 1
    You can't promise `b_` won't change what it refers to *and* pass `b_` to `b` *and* retain the rights to modify what `b` refers to. This is a contradiction. This expresses you both want to be able to modify `b_` and also promise not to modify `b_`. – François Andrieux Jan 24 '20 at 20:01
  • Ok, so in this case, I must remove the `const` from the constructor parameter, that's it? – Matheus Diógenes Andrade Jan 24 '20 at 20:02
  • 3
    FWIW, reference class member are not ideal. They stop the assignment operators from being generated. I would switch to a pointer (smart or otherwise). – NathanOliver Jan 24 '20 at 20:02
  • 1
    "*I want to express that the reference passed as a parameter to the class `A` constructor will not be used to change the values of the object `b_`.*" But if you **ever** want to modify that reference to `b_` (and so modify `b_`), you can't take it as `const`. – scohe001 Jan 24 '20 at 20:02
  • 1
    @MatheusDiógenesAndrade It depends on what you actually want to do. Right now your stated goal is a contradiction and the first step is to resolve it. Once you know what you want, you can decide whether to add `const` to `b`, remove `const` from `b_` or change your design. – François Andrieux Jan 24 '20 at 20:04
  • @FrançoisAndrieux, and scohe001, now I see, thank you. – Matheus Diógenes Andrade Jan 24 '20 at 20:05
  • 2
    @MatheusDiógenesAndrade I would recommend paying attention to NathanOliver's comment. Most of the time, if you use a reference member, you will eventually come to regret it. Using a pointer is usually better than references when it comes to class data members. – François Andrieux Jan 24 '20 at 20:07
  • But, if I put the word `const` in the `b` class attribute, will I be able in the future to change the value of reference `b`? (I am not asking if I will be able to change the object of the referece `b`). – Matheus Diógenes Andrade Jan 24 '20 at 20:08
  • @MatheusDiógenesAndrade It sounds to me like you are asking if you can change *which* object `b` refers to vs changing the value of the object currently being referred. One thing to understand about references in c++ is that once they are initialized it is impossible to change *which* object they refer to. If you want to do that you need to use a pointer instead. Edit : You may be interested in [What is the difference between const int*, const int * const, and int const *?](https://stackoverflow.com/questions/1143262/what-is-the-difference-between-const-int-const-int-const-and-int-const). – François Andrieux Jan 24 '20 at 20:14
  • 1
    @MatheusDiógenesAndrade Your questions make me think you may want to read a [good book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list#388282). It seems you don't know the language well. – Jesper Juhl Jan 24 '20 at 20:14

1 Answers1

3

I want to express that the reference passed as a parameter to the class A constructor will not be used to change the values of the object b_.

But that's not true. The reference passed to A's constructor can be modified. Not necessarily by A's constructor directly, but by whatever other member functions of A which modify the object.

If a function takes a parameter by const&, the caller of that function has the right to expect that the object will not be modified by that function or by any process dependent on that function's execution. Such as initializing a reference member in a constructor which can be accessed after that constructor's execution.

What you should do is not lie to the user. A dependent result of A's constructor is that the parameter passed to it may be modified. So it should be a non-const reference.

Equally importantly, the act of creating an A fundamentally depends on the given object continuing to exist after the constructor exits. Since a const& parameter can be bound to a temporary, it would be very easy for someone to call your constructor like this A a(B{}); a after this statement references an object that has been destroyed. If your function took a non-const reference, this would be a compile error.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982