2

I have a class member variable as

vector<std::unique_ptr<T> > v;

and a member function where I want to use a unique_ptr element of v "addressed" by an iterator argument. Which one is better?

void mem_fun(vector<std::unique_ptr<T> >::iterator it) {
    std::unique_ptr<T> p;
    p = std::move(*it);
    ...
}

Or

void mem_fun(vector<std::unique_ptr<T> >::iterator it) {
    std::unique_ptr<T>& p = *it;
    ...
}

From what I know, it seems the second way just kind of violates the "uniqueness" of unique_ptr. But can std::move() move *it (a reference)? BTW, who truly owns the unique_ptr pointers, the class, the member vector, any member function, or what else?

vincentvangaogh
  • 354
  • 3
  • 11

3 Answers3

1

The first version takes ownership of the unique_ptr's target and leaves the vector with empty unique_ptrs. It is unlikely that this is what you want. The second version is confusing. If all you want to do is access the objects managed by the unique_ptrs without affecting ownership, simply use the de-rererence operator(s):

(*it)->someMethodOfT();

Here, the de-reference (*it) is to de-reference the iterator, and the -> is to de-reference the unique_ptr.

Remember: the "uniqueness" of a unique_ptr refers to its ownership. There's nothing to say the managed object can't be accesses by many non-owners. But it is up to you to decide who takes ownership, depending on the requirements of your application.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • So does "ownership" of `unique_ptr` mean the permission to "set" and "get" the only one copy? Someone else that has no ownership but a reference can "get" but not "set"? Making another copy (e.g. calling `push_back()`) is also a "get" action? – vincentvangaogh Jul 09 '15 at 07:13
  • @WanxinGao No, it means who has control over its lifetime. When the owner dies, the managed object dies too. – juanchopanza Jul 09 '15 at 07:14
  • OK! So for `unique_ptr` anyone has the right of use ("get" and "set"), but only one has the ownership (?) – vincentvangaogh Jul 09 '15 at 07:27
  • @WanxinGao Yes, exactly. Ownership can be transferred, but there's only ever one owner. – juanchopanza Jul 09 '15 at 07:38
1

This post from Herb Sutter contains the knowledge to answer your question.

The unique_ptr actually defines an 'ownership certificate'. This ownership is not copyable. When you move the unique_ptr, this effectively destructs the certificate stored in the `vector.

Therefore, the vector<unique_ptr<T>> owns the Ts.

When you just want to do stuff with the Ts, you should declare your function as

void mem_fun(T& t) { ... }

And delegate the dereferencing to another function:

template<typename It, typename F>
void foreach_deref(It from, It to, F f) {
    std::for_each(from, to, [&](decltype(*from) &pt) {
         f(*pt);
    }
}

And use this to call your member function:

foreach_deref(begin(v), end(v), [&](T& t) { mem_fun(t); });
xtofl
  • 40,723
  • 12
  • 105
  • 192
0
p = std::move(*it);

This means, that p is now owning what was owned by *it before, and *it is no longer owning it(*).

In fact, using *it hereafter may cause undefined behaviour, since it has been moved from.

The unique_ptr behind the *it is owned by the vector. So in fact you changed your vector. I think this is not what you intended, so better use the reference version.

[...] it seems the second way just kind of violates the "uniqueness" [...]

Uniqueness in this case means a single owner of the object. You may of course have multiple references to the owner of this object (which is the pointer).


(*) This also means that when p goes out of scope, the object gets destroyed and deallocated. (Unless you moved from p somewhere)

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
  • An undefined behavior? I thought using `*it` might sets the original `unique_ptr` in the vector to `null`? – vincentvangaogh Jul 09 '15 at 07:17
  • Only dereferencing the moved from pointer will cause UB, because after `move(*it)` the pointer is set to `nullptr`. Though merely accessing (via `*it`) doesn't change anything. – Daniel Jour Jul 09 '15 at 07:26