4 ms·
Specifically, what I said was > C++ specifically gives you mutable references to express the desired behavior in these cases where "these cases" refers to the
by cpgxiii 4y ago
Specifically, what I said was
> C++ specifically gives you mutable references to express the desired behavior in these cases
where "these cases" refers to the common case of (a) having a mutable argument, (b) which you want passed by reference, and (c) do not want to be nullable, that is exactly the semantics achieved by passing via mutable reference. I am not claiming this is why Stroustrup added them (his own explanation for why references were added is "References are useful for several things, but the direct reason I introduced them in C++ was to support operator overloading."), but that the language provides a construct which provides exactly for the desired behavior.
> Pointers are a better option because they make the mutability apparent at the call site.
At the first call site, yes (sometimes, see below). Not at any further calls.
> Codebases with that convention work great. There is no special training or documentation overhead involved.
As someone who works with a large codebase following this style, I beg to differ. Codebases with this convention are littered with
ReturnType func(ParamType* param) {
assert(param != nullptr);
...
}
because mutable-arguments-via-pointer has introduced undesired nullability, where the intended behavior could have been expressed more directly as
ReturnType func(ParamType& param) {
...
}
and, it inevitably combines all three types of methods
ReturnType func1(const ParamType* param) {
if(param != nullptr) {
...
}
ReturnType func2(ParamType* param) {
assert(param != nullptr);
...
}
ReturnType func3(ParamType* param) {
if (param != nullptr) {
...
}
mingling nullability and mutability, none of which is obvious from
func1(&foo);
func2(&bar);
func3(&baz);
and you still end up needing documentation to figure out what's happening.