Disclaimer: This is rather more out of curiosity than for a lack of other solutions!
Is it possible to implement a function in C++ that:
- gets passed a pointer of type T
- either returns a reference-like-thing to the object pointed to by T
- or, if the pointer is null, returns a reference-like-thing to a default constructed
T()
that has some sane lifetime?
Our first try was:
template<typename T>
T& DefaultIfNullDangling(T* ptr) {
if (!ptr) {
return T(); // xxx warning C4172: returning address of local variable or temporary
} else {
return *ptr;
}
}
A second attempt was done like this:
template<typename T>
T& DefaultIfNull(T* ptr, T&& callSiteTemp = T()) {
if (!ptr) {
return callSiteTemp;
} else {
return *ptr;
}
}
This gets rid of the warning and somewhat extends the lifetime of the temporary, but it's still rather error prone, I think.
Background:
The whole thing was triggered by an access pattern that looked like this:
if (pThing) {
for (auto& subThing : pThing->subs1) {
// ...
if (subThing.pSubSub) {
for (auto& subSubThing : *(subThing.pSubSub)) {
// ...
}
}
}
}
that could be "simplified" to:
for (auto& subThing : DefaultIfNull(pThing).subs1) {
// ...
for (auto& subSubThing : DefaultIfNull(subThing.pSubSub)) {
// ...
}
}
If you only want to skip over
nullptrs
easily, you could just useboost::filter_iterator
. Now, this does not return default value on null pointer occurence, but neither does OP's original code; instead it wraps the container and provides the API to silently skip it in the for loop.I skipped all the boilerplate code for brevity, hopefully the snippet below illustrates the idea well.