std::vector
has the member function at()
as a safe alternative to operator[]
, so that bound checking is applied and no dangling references are created:
void foo(std::vector<int> const&x)
{
const auto&a=x[0]; // What if x.empty()? Undefined behavior!
const auto&a=x.at(0); // Throws exception if x.empty().
}
However, std::unique_ptr
lacks the corresponding functionality:
void foo(std::unique_ptr<int> const&x)
{
const auto&a=*x; // What if bool(x)==false? Undefined behavior!
}
It would be great, if std::unique_ptr
had such a safe alternative, say member ref()
(and cref()
) which never returns a dangling reference, but rather throws an exception. Possible implementation:
template<typename T>
typename add_lvalue_reference<T>::type
unique_ptr<T>::ref() const noexcept(false)
{
if(bool(*this)==false)
throw run_time_error("trying to de-refrence null unique_ptr");
return this->operator*();
}
Is there any good reason why the standard doesn't provide this sort of thing?
std::unique_ptr<int[]> pFoo(new int[n]);
which can't be done. – Plumate*(unique_ptr<int>(NULL))
, albeit the latter will most likely segfault. – Truckloadstd::undefined_pointer_exception
or similar. Since you can check for the validity of the pointers manually, the omission of the exception actually seems odd. – Truckloadnullptr
is the only invalid pointer you can (portably) test for, so the function isn't very safe, or even useful, at all. – Adrenalineassert(x)
to check the pointer, but I cannot catch the assertion.std::unique_ptr
has a well defined invalid state that is not exposed to try/catch error handling. Of course it's not required, but it also another sinkhole down to undefined behavior when it would actually be possible to have defined behavior (even if you explicitly need to request it). Sounique_ptr::get()
(opposite tooperator*()
) could actually throw for invalid pointers. It doesn't. – Truckloadvector.at()
would be the same as the one behind anunique_ptr.at()
, but what I wonder is whyvector.at()
exists. When you dereference a null pointer or access outside of an array... Then what ? You were going to use an object, but there's no object there. That's not an exceptional condition, but an invariant failure. Plus, if you want a meaningful exception, you need to intercept the null dereference, and throw your own exception from context. Andif(!p) throw ...;
looks better thantry {...} catch(...) { throw ...; }
. – Fragranceif()
statement and instead have atry...catch
? Honestly, I didn't know thatvector.at()
was a function for a long time - I just checked the bounds of the vector before accessing it. But then again, I tend to use the "check preconditions" model rather than having exception handling everywhere (not saying either way is better). – Sultanaunique_ptr
I can say that there are lots of good answers here, and several good suggestions on how to get the behavior you want. And of those, none of them are demonstrably better than any of the rest. If one answer were to be standardized, someone would ask: "How come it wasn't done the other way?" And before you know it, theunique_ptr
API would look a lot like thestring
API: bloated. The current API forunique_ptr
is sufficient for you to do whatever you want to. No further help from the standard is needed. – Calabrovector
anat()
butunique_ptr
noref()
)? – Anthea