0

I have a data structure consisting of few 'blocks'. For each block I have mutex. I want to implement a method that locks entire data structure and move this lock to calling function. Here's my code:

std::vector<std::unique_lock<boost::shared_mutex>> lock_array() 
{
    std::vector<std::unique_lock<boost::shared_mutex>> locks;
    for(size_t block = 0; block < BLOCK_COUNT; ++block)
    {
        locks.push_back(std::unique_lock<boost::shared_mutex>(mutexes[block]));
    }
    return std::move(locks);
}

And if I call it in such way, will my array still be locked?

void some_method()
{
    auto locks = lock_array();
    ...
}
billz
  • 44,644
  • 9
  • 83
  • 100
Evgeny Eltishev
  • 593
  • 3
  • 18
  • Just an FYI - the std::move technically isn't required because the compiler can do return value optimization and move the result out implicitly. – Mike Weller Jul 23 '13 at 09:56
  • @MikeWeller: Besides RVO not being mandated, to return by copy, a copy ctor needs to be present, wether optimized out or not. – PlasmaHH Jul 23 '13 at 09:59
  • RVO is not such thing that I can rely here, because it's not guaranteed that it will be used – Evgeny Eltishev Jul 23 '13 at 10:01
  • 1
    locks still locked because they acquire lock during construction and will destroy only when locks go out of scope. and `std::move(locks);` won't help here as Mike mentioned. – billz Jul 23 '13 at 10:03
  • But you don't need the `std::move` anyway. It inhibits RVO, and it doesn't add anything: if you just `return locks`, you will either get RVO, or a move. – juanchopanza Jul 23 '13 at 10:06
  • @juanchopanza is it guaranteed by the standard that RVO or move will be used for sure? – Evgeny Eltishev Jul 23 '13 at 10:08
  • if you are confused by rvo, copy, move, read http://stackoverflow.com/questions/13618506/is-it-possible-to-stdmove-objects-out-of-functions-c11/13618587#13618587 – billz Jul 23 '13 at 10:09
  • 1
    @EvgenyEltishev: Yes, the standard guarantees that it will be either moved, or the move will be elided. C++11 12.8/32 describes how the return expression is treated as an *rvalue* if possible, so that the move constructor will be selected. – Mike Seymour Jul 23 '13 at 10:33
  • 1
    It is guaranteed that move will be used if RVO hasn't been used, and if the types involved have move constructors. – juanchopanza Jul 23 '13 at 10:33
  • @plasma a move ctor is enough. – Yakk - Adam Nevraumont Jul 23 '13 at 10:38
  • @Yakk: a move ctor does not copy. – PlasmaHH Jul 23 '13 at 10:44
  • @PlasmaHH: But return values are moved if possible, so a move constructor is enough to return a value from a function. I'm not sure why you're talking about returning by copy, since the question is about returning an uncopyable (but movable) type. – Mike Seymour Jul 23 '13 at 10:48
  • @PlasmaHH Yes, a move ctor does not copy. And the sky is blue. And leopards have spots. Despite these and other interesting facts, a move ctor is enough to return a local variable from a function, and that move ctor can be elided. – Yakk - Adam Nevraumont Jul 23 '13 at 12:01

2 Answers2

3

Yes. Moving a unique_lock will preserve the lock, and moving the vector should not affect the locks at all. You could verify this:

void some_method()
{
    auto locks = lock_array();
    for (auto const & lock : locks) {
        assert(lock.owns_lock());
    }
}

Also, note that you don't need std::move when returning; return values are moved anyway (unless the move is elided).

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
1

You transferred locks out of lock_array() function, compiler should use RVO or move locks out of lock_array(), otherwise you will get compiler error as unique_lock is moveable but not copyable.

locks still locked because they acquire lock during construction and will destroy only when locks go out of scope. Your transfer action won't destroy locks.

§ 30.4.2.2

An object of type unique_lock controls the ownership of a lockable object within a scope. Ownership of the lockable object may be acquired at construction or after construction, and may be transferred, after acquisition, to another unique_lock object. Objects of type unique_lock are not copyable but are movable.

billz
  • 44,644
  • 9
  • 83
  • 100