What's with unique_ptr::get() instead of &*? - c++

I'm using unique_ptr to manage some resources for safe destruction in every circumstance, etc.
void do_something(BLOB* b);
unique_ptr<BLOB> b(new_BLOB(20));
Is &* much worse than get? e.g.
do_something(&*b);
or
do_someting(b.get());
both seem to work.

The operator* of std::unique_ptr has undefined behavior if no memory is owned by the unique_ptr where as get() will return nullptr.
If the unique_ptr could ever be empty I would suggest using get() otherwise there is no difference.

&*b is not necessarily equivalent to b.get(). In order to be sure to recieve a pointer to the managed object, you want to use get().
There are two reasons:
Calling operator* on a unique_ptr not managing any object is undefined behaviour
The managed object of type T may overload operator& and as such you may not recieve a valid pointer to T.
The standard defines the bevaiour of operator* of std::unique_ptr:
typename add_lvalue_reference<T>::type operator*() const;
Requires: get() != nullptr
Returns: *get()
Thus, applying operator* (from &*) is not allowed if get() returns nullptr.
You will get the return value of any overloaded operator& in the managed object if present. This can be circumvented by using std::addressof but the undefined behaviour problem persists.
std::unique_ptr<T>::get() will give you the address of the managed object or nullptr if no object is managed. It is safer to use get() and you have a predictable result.

As has been pointed out by other answers, if the unique_ptr does not manage any object, use of &* leads to undefined behavior.
For cases where unique_ptr manages a pointer, in most cases,
do_something(&*b);
is equivalent to
do_someting(b.get());
The only time you could get different results is if BLOB has an operator& overload that returns a pointer that is different than the address of the object.

This is really an opinion based question.
I happen to think &*ptr looks ugly and it isn't clear to a reader why it is written like that. But it does have the advantage that it works with smart pointers and regular pointers.

Related

Function returns const ref to std::unique_ptr, can it return null?

I have a function that return const ref to a std::unique_ptr. I'm getting this ptr from some container. I want to have a possibility to return nullptr or something when in my container of std::unique_ptr there is no appropriate object to the input values. It seems to be impossible with const ref. There is definitely an option to return const raw pointer, but I would like to stick to std::unique_ptr if it's possible.
If you have an interface that returns a reference to an object, then that interface is referring to an object that exists somewhere in the program. If, in the course of trying to generate such a reference, you realize that the user has malformed their inputs or otherwise no such object exists, you have the following choices:
Throw an exception. This is typically how we recognize cases where the user of a function did something wrong, that they asked for a thing that didn't exist.
Change the function to return by value instead of by reference. In this case, it would probably be a naked pointer value, rather than a reference.
In any case, there is pretty much no reason to explicitly return an lvalue reference to a unique_ptr from any API. unique_ptr represents ownership, and if an API directly shows one, it should represent a transfer of ownership from the source to the destination. A function that returns an rvalue-reference to a unique_ptr means that it is giving the caller ownership of the object being pointed to.
If no transfer of ownership is taking place, you shouldn't be using unique_ptr in the API.
Note that there is a difference between a container that knows that it contains a unique_ptr and a container that happens to contain a unique_ptr. vector<T> is a generalized array, so the fact that operator[] returns a T& is OK even if that T happens to be unique_ptr. It is the user of the container who knows what that T means and how to use it.
By contrast, if your container is conceptually a container of unique_ptrs, then its API should recognize this fact.
class A {
public:
const std::unique_ptr<B>& function() {
return m_uni;
}
private:
std::unique_ptr<B> m_uni{nullptr};
};
This works and the returned unique_ptr is nullptr. Yes it is allowed and possible. Still, returning references to unique_ptr is kind of a code smell. If you can share more about why you want to use unique_ptr and what you are using this container for, someone may be able to provide an alternative.
The modifiers on the unique_ptr variable itself (const, &, *) have nothing to do with the value stored in the unique_ptr.

What is the difference between *smart_ptr and *smart_ptr.get()

As well as I understand, dereferencing - *smart_ptr , and get() + dereferencing *smart_ptr.get() doing the same thing with smart pointers, but may be there is something under the hood that I'm not aware of, cause I've seen a lot of cases there the second approach was used, so what is the point? Does it affect performance in any way?
There is no difference. The standard in [unique.ptr.single.observers] and [util.smartptr.shared.obs] both define operator* as being *get().
get should be used when you need a raw pointer to the managed object for passing to something that only excepts a raw pointer. Otherwise, * and -> are overloaded for the smart pointers to apply those operations to the managed pointer.
You could be tempeted to use &*smart_ptr to get a raw pointer to the managed object, but & is an operator that can be overloaded and could give you the wrong result. the proper way to get the address (a pointer) would be std::addressof(*smart_ptr), but using smart_ptr.get() is shorter.
From a functional standpoint, there is no difference between *smart_ptr and *(smart_ptr.get()), as they are defined in the C++ standard as doing the same thing - dereference the held pointer and return a reference to the object being pointed at.
However, from a debugging standpoint, there may be a subtle difference, depending on implementation. get() is defined as returning the held pointer as-is, whether it is nullptr or not. The smart pointer has no concept of what the caller will do with that pointer afterwards. However, dereferencing a nullptr is undefined behavior, and knowing that, it is possible that a smart pointer implementation MAY decide to have its operator* throw a runtime error if the held pointer cannot be dereferenced, to aid with debugging efforts.
This is mentioned on cppreference, at least for std::unique_ptr::operator*:
may throw, e.g. if pointer defines a throwing operator*

Does it make sense to combine optional with reference_wrapper?

It occurred to me that in C++ it is possible to use the type std::optional<std::reference_wrapper<T>>. An object of this type is essentially a reference to an object of type T or a null value, i.e., pretty much a pointer. My questions:
Is there any conceptual difference between std::optional<std::reference_wrapper<T>> and T*?
Is there any practical difference? Are there situations where it might be advisable to choose std::optional<std::reference_wrapper<T>> over T*?
Is there any conceptual difference between std::optional<std::reference_wrapper<T>> and T*?
std::optional<>, as the name already suggest, is meant to be used when we could have a value or might not have any value at all.
The equivalent of having no value for a T* object would be assigning nullptr to it, i.e.: the pointer will point to nowhere, as opposed to somewhere (or even anywhere, i.e.: uninitialized). It can be said that std::optional<> exports the concept of nullptr for pointers to any arbitrary type. So, I would say they are conceptually very similar, being the std::option<> approach a kind of generalization.
Is there any practical difference? Are there situations where it might be advisable to choose std::optional<std::reference_wrapper<T>> over T*?
I can think of the size. std::optional<> contains an internal flag for indicating the presence/absence of a value, whereas for T* the nullptr is encoded directly as one of the values the pointer can store. So a std::optional<std::reference_wrapper<T>> object will be larger than a T*.
When it comes to safety, unlike T*, std::optional<> provides the member function value() which throws an exception if there is no value (it provides as well as the unsafe operator*() as T* does).
Also, using std::optional<std::reference_wrapper<T>> instead of T* , for example, as a function's return value may indicate in a more explicit way that there might be no value at all.
The main difference between std::optional<std::reference_wrapper<T>> and T* is that with T* you have to think about who owns the memory that is pointed to.
If a function returns T* you have to know if you are responsible for freeing the memory or someone else is. That's not something you have to be concerned with when it's a reference.

Check for null in std::shared_ptr

I was wondering if i need to check whether sp is null before i use it.
Correct me if I am wrong but creating an alias will not increase the ref counter and therefore by entering into the method we are working with a shared pointer which we don't know if the embedded pointer has been reset before.. am I correct by assuming this?
Class::MyFunction(std::shared_ptr<foo> &sp)
{
...
sp->do_something();
...
}
You have to consider that std::shared_ptr is overall still a pointer (encapsulated in a pointer like class) and that it can indeed be constructed to internally be nullptr. When that happens, expressions like:
ptr->
*ptr
leads to undefined behavior. So, yeah, if you are expecting the pointer to also be nullptr, then you should check for its value with:
ptr != nullptr
or
!ptr
(thanks to its operator bool).
Most shared pointers are exactly like normal pointers in this
respect. You have to check for null. Depending on the
function, you may want to switch to using
void myFunction( Foo const& foo );
, and calling it by dereferencing the pointer (which pushes the
responsibility for ensuring that the pointer is not null to the
caller).
Also, it's probably bad practice to make the function take
a shared pointer unless there are some special ownership
semantics involved. If the function is just going to use the
pointer for the duration of the function, neither changing it or
taking ownership, a raw pointer is probably more appropriate,
since it imposes less constraints on the caller. (But this
really depends a lot on what the function does, and why you are
using shared pointers. And of course, the fact that you've
passed a non-const reference to the shared pointer supposes that
you are going to modify it, so passing a shared pointer might be
appropriate.)
Finally, different implementations of shared pointers make it
more or less difficult to check for null. With C++11, you can
use std::shared_ptr, and just compare it to nullptr
naturally, as you'd expect. The Boost implementation is a bit
broken in this respect, however; you cannot just compare it to
0 or NULL. You must either construct an empty
boost::shared_ptr for the comparison, or call get on it and
compare the resulting raw pointer to 0 or NULL.
There is no point in passing a shared_ptr as reference.
You can obtain the internal object via boost::shared_ptr<T>.get() and check for nullptr
Also relevant: move to std :)
Edit: This is the implementation: http://www.boost.org/doc/libs/1_55_0/boost/smart_ptr/shared_ptr.hpp
And here is a SO thread about ref or no ref: Should I pass a shared_ptr by reference?
It uses move semantics when Cx11 and copies two ints otherwise which is slower than passing a reference but when is somebody on this level of optimization?
There's no general answer to this question. You have to treat it just like any other pointer. If you don't know whether it's null, test. If you believe it to never be null, assert() that it's not null and use it directly.
The fact that you have a reference to shared_ptr, or even that you have a shared_ptr, has no impact here.

Can I cast shared_ptr<T> & to shared_ptr<T const> & without changing use_count?

I have a program that uses boost::shared_ptrs and, in particular, relies on the accuracy of the use_count to perform optimizations.
For instance, imagine an addition operation with two argument pointers called lhs and rhs. Say they both have the type shared_ptr<Node>. When it comes time to perform the addition, I'll check the use_count, and if I find that one of the arguments has a reference count of exactly one, then I'll reuse it to perform the operation in place. If neither argument can be reused, I must allocate a new data buffer and perform the operation out-of-place. I'm dealing with enormous data structures, so the in-place optimization is very beneficial.
Because of this, I can never copy the shared_ptrs without reason, i.e., every function takes the shared_ptrs by reference or const reference to avoid distorting use_count.
My question is this: I sometimes have a shared_ptr<T> & that I want to cast to shared_ptr<T const> &, but how can I do it without distorting the use count? static_pointer_cast returns a new object rather than a reference. I'd be inclined to think that it would work to just cast the whole shared_ptr, as in:
void f(shared_ptr<T> & x)
{
shared_ptr<T const> & x_ = *reinterpret_cast<shared_ptr<T const> *>(&x);
}
I highly doubt this complies with the standard, but, as I said, it will probably work. Is there a way to do this that's guaranteed safe and correct?
Updating to Focus the Question
Critiquing the design does not help answer this post. There are two interesting questions to consider:
Is there any guarantee (by the writer of boost::shared_ptr, or by the standard, in the case of std::tr1::shared_ptr) that shared_ptr<T> and shared_ptr<T const> have identical layouts and behavior?
If (1) is true, then is the above a legal use of reinterpret_cast? I think you would be hard-pressed to find a compiler that generates failing code for the above example, but that doesn't mean it's legal. Whatever your answer, can you find support for it in the C++ standard?
I sometimes have a shared_ptr<T> & that I want to cast to shared_ptr<T const> &, but how can I do it without distorting the use count?
You don't. The very concept is wrong. Consider what happens with a naked pointer T* and const T*. When you cast your T* into a const T*, you now have two pointers. You don't have two references to the same pointer; you have two pointers.
Why should this be different for smart pointers? You have two pointers: one to a T, and one to a const T. They're both sharing ownership of the same object, so you are using two of them. Your use_count therefore ought to be 2, not 1.
Your problem is your attempt to overload the meaning of use_count, co-opting its functionality for some other purpose. In short: you're doing it wrong.
Your description of what you do with shared_ptrs who's use_count is one is... frightening. You're basically saying that certain functions co-opt one of its arguments, which the caller is clearly using (since the caller obviously is still using it). And the caller doesn't know which one was claimed (if any), so the caller has no idea what the state of the arguments is after the function. Modifying the arguments for operations like that is usually not a good idea.
Plus, what you're doing can only work if you pass shared_ptr<T> by reference, which itself isn't a good idea (like regular pointers, smart pointers should almost always be taken by value).
In short, you're taking a very commonly used object with well-defined idioms and semantics, then requiring that it be used in a way that they are almost never used, with specialized semantics that work counter to the way everyone actually uses them. That's not a good thing.
You have effectively created the concept of co-optable pointer, a shared pointer that can be in 3 use states: empty, in use by the person who gave it to you only and thus you can steal from it, and in use by more than one person so you can't have it. It's not the semantics that shared_ptr exists to support. So you should write your own smart pointer that provides these semantics in a much more natural way.
Something that recognizes the difference between how many instances of a pointer you have around and how many actual users of it you have. That way, you can pass it around by value properly, but you have some way of saying that you are currently using it and don't want one of these other functions to claim it. It could use shared_ptr internally, but it should provide its own semantics.
static_pointer_cast is the right tool for the job — you've already identified that.
The problem with it isn't that it returns a new object, but rather that it leaves the old object unchanged. You want to get rid of the non-const pointer and move on with the const pointer. What you really want is static_pointer_cast< T const >( std::move( old_ptr ) ). But there isn't an overload for rvalue references.
The workaround is simple: manually invalidate the old pointer just as std::move would.
auto my_const_pointer = static_pointer_cast< T const >( modifiable_pointer );
modifiable_pointer = nullptr;
It might be slightly slower than reinterpret_cast, but it's a lot more likely to work. Don't underestimate how complex the library implementation is, and how it can fail when abused.
An aside: use pointer.unique() instead of use_count() == 1. Some implementations might use a linked list with no cached use count, making use_count() O(N) whereas the unique test remains O(1). The Standard recommends unique for copy on write optimization.
EDIT: Now I see you mention
I can never copy the shared_ptrs without reason, i.e., every function takes the shared_ptrs by reference or const reference to avoid distorting use_count.
This is Doing It Wrong. You've added another layer of ownership semantics atop what shared_ptr already does. They should be passed by value, with std::move used where the caller no longer desires ownership. If the profiler says you're spending time adjusting reference counts, then you might add some references-to-pointer in the inner loops. But as a general rule, if you can't set a pointer to nullptr because you're no longer using it, but someone else might be, then you've really lost track of ownership.
If you cast a shared_ptr to a different type, without changing the reference count, this implies that you'll now have two pointers to the same data. Hence, unless you erase the old pointer, you can't do this with shared_ptrs without "distorting the reference count".
I would suggest that you use raw pointers here instead, rather than going out of your way to not use the features of shared_ptrs. If you need to sometimes create new references, use enable_shared_from_this to derive a new shared_ptr to an existing raw pointer.
When it comes time to perform the addition, I'll check the use_count, and if I find that one of the arguments has a reference count of exactly one, then I'll reuse it to perform the operation in place.
This isn't necessarily valid unless you're applying some other rules across the whole program to make it so. Consider:
shared_ptr<Node> add(shared_ptr<Node> const &lhs,shared_ptr<Node> const &rhs) {
if(lhs.use_count()==1) {
// do whatever, reusing lhs
return lhs;
}
if(rhs.use_count()==1) {
// do whatever, reusing rhs
return rhs;
}
shared_ptr<Node> new_node = ... // do whatever without reusing lhs or rhs
return new_node;
}
void foo() {
shared_ptr<Node> a,b;
shared_ptr<Node> c = add(a,b);
// error, we still have a and b, and expect that they're unchanged! they could have been modified!
}
Instead if you take the smart pointers by value:
shared_ptr<Node> add(shared_ptr<Node> lhs,shared_ptr<Node> rhs) {
And the use_count()==1 then you know that your copy is the only one and it should be safe to reuse it.
However, there's a problem in using this as an optimization, because copying a shared_ptr requires synchronization. It could well be that doing all this synchronization all over the place costs far more than you save by reusing existing shared_ptrs. All this synchronization is the reason it's recommended that code that does not take ownership of a shared_ptr should take the shared_ptr by reference instead of by value.