0

Suppose i have something akin to this pseudocode:

std::optional<std::pair<double*, std::scope_lock<std::mutex> > > getDataTogetherWithLock() {
  if (!some_ptr) {
    return std::nullopt;
  }
  return some_ptr->getDataTogetherWithLock();//just returns std::pair<double*, std::scope_lock<std::mutex> >
}

This won't work, basicly if tried with real code will give an error about the return type cannot be converted to std::optional.

What's the best way to solve this conundrum ?

darune
  • 10,480
  • 2
  • 24
  • 62
  • You specifically say non-copyable. But this might be a case where moving is more appropriate. – MSalters Feb 28 '20 at 13:04
  • @MSalters I would say moving is fine - but how ? – darune Feb 28 '20 at 13:04
  • 1
    Agree - if you're fine with moving, then post a minimal example. Doesn't have to compile of course, but it should not compile because of the precise same error as your real example has. – MSalters Feb 28 '20 at 13:09

1 Answers1

1

The problem is that std::scoped_lock itself is neither movable nor copyable. So the return value of the member function cannot be copied/moved into the return value of the function you posted. The fix is simple. Use an std::unique_lock that is moveable. The following test code compiled for me on gcc

#include <optional>
#include <mutex>

struct A {
    std::pair<double*, std::unique_lock<std::mutex> > getDataTogetherWithLock();
} *some_ptr;

std::optional<std::pair<double*, std::unique_lock<std::mutex> > > getDataTogetherWithLock() {
  if (!some_ptr) {
    return std::nullopt;
  }
  return some_ptr->getDataTogetherWithLock();
}

With std::scoped_lock it would fail to compile.

patatahooligan
  • 3,111
  • 1
  • 18
  • 27
  • 1
    @darune Not according to [cppreference](https://en.cppreference.com/w/cpp/thread/scoped_lock/scoped_lock) or gcc trunk. – patatahooligan Feb 28 '20 at 13:11
  • 3
    @darune: No, it has a deleted copy ctor and no move ctor. That's intentional. As the name says, it's a block-scope lock. – MSalters Feb 28 '20 at 13:11
  • @MSalters are you sure it's not in there as a default impl. , seems to compile on my side and seems logically ok (i think) to move around locks – darune Feb 28 '20 at 13:15
  • @darune: I'm not familiar with every implementation. I agree with patatahooligan, `unique_lock` is the more portable solution. – MSalters Feb 28 '20 at 13:20
  • @darune See [here](https://en.cppreference.com/w/cpp/language/move_constructor). If there exists a user-defined copy-constructor, there is no implicitly declared move-constructor. So the code in your OP attempts to use the copy-constructor which is deleted. If some code that looks like it moves the lock compiled then it is likely a case of guaranteed copy elision or non-standard behavior. – patatahooligan Feb 28 '20 at 13:21
  • @patatahooligan im not convinced that deleted also means user-defined – darune Feb 28 '20 at 13:25
  • @darune That was a typo on my part. The page I linked to says "[if] there are no user-*declared* copy constructors". – patatahooligan Feb 28 '20 at 13:28
  • it didn't compile in the end anyway :) thanks for the help guys and pointing me to unique_lock – darune Feb 28 '20 at 13:36