Why is std::reference_wrapper not default constructible?
Asked Answered
C

1

20

I feel that preventing std::reference_wrapper<T> to be default constructible makes it much harder to use, even though using a default constructed reference_wrapper causes a runtime exception.

However, a reference_wrapper is perfectly copyable, so it's value can always be changed, so why preventing it to have the null reference by default? It makes many usage cases much simpler and with it, the proposed observer_ptr is not needed anymore - why need the redundancy? A default constructible reference_wrapper would rule them all!

Thoughts?

Cb answered 9/1, 2017 at 5:34 Comment(6)
Perhaps you want to know that Tony Hoare, the inventor of the null reference, later referred to his invention as "a billion dollar mistake". No, we don't want nullable references by default thank you very much.Noncommittal
Haha, you are welcome. ;-)Cb
I agree. Without a default constructor, the creation of a std::array of reference_wrappers is pure pain. In addition to the default constructor, however, one would further need an assignment operator taking the wrapped references.Fortnightly
@Fortnightly I don't see creating an std::array of a non-default-constructible type as painful; you either just specify the elements in the initialiser, or you write a not-too-difficult (and better since C++14) helper function that recursively generates the elements using a lambda (passing the index, in the case of my own helper for this). Also, if this is what you meant, reference-wrapper already does have operator=(reference_wrapper) that rebinds from the RHS. If you instead meant you would want assignment to assign between the referred objects instead, that'd totally break containers.Frill
Anyway, since C++17: If you want a default-constructible std::reference_wrapper with an empty state, just put it inside an std::optional.Frill
@underscore_d: Don't get me wrong, I implemented it back then in the way you outlined, and also enjoyed it, but for somebody coming from any other language (Java, C#, Python, whatever), it is pain. Thanks for your advice using std::optional, that makes it better indeed.Fortnightly
R
17

However, a reference_wrapper is perfectly copyable, so it's value can always be changed, so why preventing it to have the null reference by default?

What would be the point of std::reference_wrapper to have a null value? If you need to have a null value, just use a pointer :P

std::reference_wrapper is built as a wrapper to a reference, that's it. It must behave like a reference would, or else it wouldn't be a wrapper but something else. There are use-cases for it, which would possibly break if you allow a default value for it. If you need to have a null value, either use something else, like a pointer, or live with the limitations of references.

Also, you state a reason yourself:

[...] even though using a default constructed reference_wrapper causes a runtime exception.

What's the point in having a reference to nothing? Having a std::reference_wrapper implies that it refers to something, just like a reference would. Adding a null value would just mean additional code every time the reference is used to see if it is null or not.

It makes many usage cases much simpler [...]

Yes, maybe. But it'll make other use-cases much harder. You'll need to check if the wrapper is valid or not, don't forget to initialize it when used as a member with a default constructor, and more.

In short, std::reference_wrapper is just a wrapper to a reference, and as such cannot behave as something else than just a plain reference. Everything has an advantage and a disadvantage, here, you might need std::observer_ptr, but in other cases, you don't need to do any checks.

Repudiation answered 9/1, 2017 at 6:0 Comment(6)
I would argue that reference can be dangling, having it being able to be default constructed to a null reference at least offers some level of determinism than dangling. Also, it would also be useful to assign a default constructed null reference or reset a reference wrapper to null, after I know that a reference is now dangling, and I want other parts of dependent logic know this fact.Cb
E.g. I can have a pre-allocated array of reference_wrappers initially nulled out, and I can assign valid references to the available entries, and after use I can reset the references back to null, nice and easy. Much nicer to use than the current definition, which doesn't even allow pre-allocated reference_wrapper containers, disabling a lot of potential use case scenarios.Cb
@Cb You have nullable pointers. Does nullability help you determine if a pointer is dangling?Noncommittal
@n.m. it doesn't help determine if a pointer is dangling, but nullptr is specifically designed in the history of C/C++ programming to signify that something is not assigned, and it's the only deterministic way to tell if I have something that needs assignment before use. That's why a pointer is even implicitly convertible to bool, meaning null is false, otherwise it's true (even if the value of the pointer is 0x01!) - probably in the world of computer programming, nullptr is the only deterministic default value to say "not usable" - not 0 (int), not false (bool), not "" (string), etc.Cb
Nullptr is inherited from C which is inherited from whatever was the C predecessor which inherited it way back from Algol W. Only the nullptr identifier is added to C++ to counteract the essentially typeless nature of the legacy NULL. See my other comment about Algol W. Anyway if you need a nullable assignable reference, just use a pointer, because that's what the pointer is. The rest of us specifically asked for reference which is NOT nullable.Noncommittal
"and as such cannot behave as something else than just a plain reference." - a reference is not reassignable, a reference_wrapper is. so it's not exactly a referenceFreehold

© 2022 - 2024 — McMap. All rights reserved.