I'm trying to create a very simple, bare-bones C++ class to implement a thread-safe list, i.e. one which is automatically locked when you access it. Unfortunately, the compiler doesn't want to allow me to create and return a struct that contains a unique_lock. This is what I tried at first:
template<typename T>
struct LockedQueue {
private:
std::mutex mutex;
using lock_t = std::unique_lock<std::mutex>;
std::list<T> underlying_list;
public:
struct LockedListAccess {
private:
lock_t lock;
public:
std::list<T> &access;
};
LockedListAccess locked() {
return LockedListAccess{ lock_t{mutex}, underlying_list };
}
};
This fails with
no matching function for call to ‘LockedQueue<tcp::socket>::LockedListAccess::LockedListAccess(<brace-enclosed initializer list>)
I'm guessing this means that brace initializer lists/C++11 unified initialization for structs don't work with move-only types like std::unique_lock. So I tried creating an explicit constructor for my struct that takes the unique_lock as an rvalue reference, and moves it into the member:
template<typename T>
struct LockedQueue {
private:
std::mutex mutex;
using lock_t = std::unique_lock<std::mutex>;
std::list<T> underlying_list;
public:
struct LockedListAccess {
private:
lock_t lock;
public:
std::list<T> &access;
LockedListAccess(lock_t&& l, std::list<T>& a) :
lock(l), access(a) {};
};
LockedListAccess locked() {
return LockedListAccess{ std::move(lock_t{mutex}), underlying_list };
}
};
However, this also fails, giving me the error
error: use of deleted function ‘std::unique_lock<_Mutex>::unique_lock(const std::unique_lock<_Mutex>&) [with _Mutex = std::mutex]’
This compiler error is especially confusing, because it points at the line containing lock(l), access(a) as the one where I'm trying to use the deleted copy constructor of std::unique_lock. I declared l as a lock_t&&, so how could I possibly be calling the copy constructor?
Most resources I could find on the internet seem to indicate that you can move unique_locks around with std::move, though no one seems to address the question of how to construct an object that contains a unique_lock by using std::move. What could I be doing wrong here?
Problem:
In the context of the LockedListAccess constructor, lock_t&& l is actually an l-value. So you need to cast it back to an r-value using std::move. General rule of thumb: Always std::move r-value references and always std::forward forwarding references.
Solution:
LockedListAccess(lock_t&& l, std::list<T>& a)
: lock(std::move(l))
, access(a)
{}
Also you do not need to move the temporary lock object because the compiler will automatically bind a temp object to an r-value reference.
This:
LockedListAccess locked() {
return LockedListAccess{ std::move(lock_t{mutex}), underlying_list }
}
can become this:
LockedListAccess locked() {
return LockedListAccess{ lock_t{mutex}, underlying_list }
}
Related
Having an object and a mutex as 2 different variables is kinda error prone
MyObject myObject;
std::mutex myObjectMutex;
I tend to forget to lock it sometimes.
On Rust, a shared object is required to be inside a mutex:
std::sync::Mutex<MyObject> mySharedObject
So I have to use like this:
mySharedObject.lock().unwrap().objectMethod()
What would be the less error prone way to simulate something like this in C++ so I don't forget to lock it?
I thought of an std::tuple<std::mutex, MyObject> but it's not very good and I can forget to lock.
One way to do it is have your Mutex<T> only allow access to the contained T via a lambda:
template <typename T>
class Mutex {
private:
T value;
std::mutex mutex;
public:
// Fill out some constructors, probably some kind of emplacement constructor too.
// For simplicity of the example, this should be okay:
explicit Mutex(T value)
: value(std::move(value))
{}
template <typename F>
auto locked(F&& fn) const& -> std::invoke_result_t<F&&, T const&> {
// Lock the mutex while invoking the function.
// scoped_lock automatically unlocks at the end of the scope
std::scoped_lock lock(mutex);
return std::invoke(std::forward<F>(fn), value);
}
template <typename F>
auto locked(F&& fn) & -> std::invoke_result_t<F&&, T&> {
std::scoped_lock lock(mutex);
return std::invoke(std::forward<F>(fn), value);
}
// Can be worth repeating for const&& and && as well
};
Usage:
mySharedObject.locked([] (MyObject& obj) { return obj.objectMethod(); });
It's still possible to defeat this by stashing a reference to the obj inside a .locked(...) call and using the reference outside of .locked(...), but that would almost require deliberately trying to do the wrong thing.
Also, be aware that it being in a lambda can be quite limiting, as regular control flow no longer works (return doesn't return from the outer scope, continue/break don't work, etc.)
I think the following is very near regardless of the lifetime parameter
#include <atomic>
template<class T>
class MutexGuard{
T& inner;
std::atomic_flag & locked;
public:
MutexGuard(T& inner, std::atomic_flag& locked): inner{inner}, locked{locked}{}
operator T&()&{
return inner;
}
~MutexGuard(){
locked.clear();
}
};
template<class T>
class Mutex{
std::atomic_flag locked{false};
T inner;
public:
Mutex(T&& inner):inner{std::move(inner)}{}
Mutex(const T&) = delete;
MutexGuard<T> lock(){
while(locked.test_and_set());
return MutexGuard<T>{inner, locked};
}
};
Demo
I'd like to initialize a static std::map where the value is not copyable. I'll call my class ValueClass. ValueClass has an std::unique_ptr as private member and I even ensure that ValueClass is not copyable by extending non_copyable that looks like the following:
class non_copyable {
public:
non_copyable() = default;
protected:
virtual ~non_copyable() = default;
private:
non_copyable(const non_copyable&) = delete;
non_copyable& operator=(const non_copyable&) = delete;
};
Now I'm trying to define a std::map using my class as value:
static std::map<int, ValueClass> value_classes = {
{0, ValueClass()},
{1, ValueClass() }
};
I get compilation error as initializer_list tries to copy this class.
I've tried to write my own make_map function whole this weekend during many hours to enable initialization without copying but I've failed. I've tried this, that and other but none of them compile with Visual Studio 15.9.4.
How can I initialize static std::map where copy is not forced, and the initialization is uniformed in one function, using Visual Studio compiler?
EDIT:
Here is the simplified version of the real life scenario where I'm trying to get this working (forgive me for lack of naming convention and inconsistency for cases):
#include <iostream>
#include <map>
class non_copyable {
public:
non_copyable() = default;
protected:
virtual ~non_copyable() = default;
private:
non_copyable(const non_copyable&) = delete;
non_copyable& operator=(const non_copyable&) = delete;
};
class InnerValueClass : public non_copyable
{
public:
InnerValueClass(const int inner_number) : inner_number_(inner_number) { }
private:
int inner_number_;
};
class ValueClass : public non_copyable
{
public:
ValueClass(const int number1) : number1_(number1) { }
ValueClass(const bool condition) : condition_(condition), inner_value_(
std::make_unique<InnerValueClass>(5)) { }
private:
int number1_{};
bool condition_{};
std::unique_ptr<InnerValueClass> inner_value_{};
};
/* Inline initialization of std::map copies, this is for initialization of non-copy types*/
template <typename TKey, typename TNonCopyableValue>
class make_map_by_moving
{
typedef std::map<TKey, TNonCopyableValue> map_type;
map_type map_;
public:
make_map_by_moving(const TKey& key, TNonCopyableValue&& val)
{
map_.emplace(key, std::move(val));
}
make_map_by_moving<TKey, TNonCopyableValue>& operator()(const TKey& key, TNonCopyableValue&& val)
{
map_.emplace(key, std::move(val));
return *this;
}
operator const map_type&()
{
return map_;
}
};
static std::map<int, ValueClass> map =
make_map_by_moving<int, ValueClass>
(1, ValueClass(5))
(2, ValueClass(true));
/* It goes on like this for hundreds of lines, so I really appreciate any
solution that leave me with a clean initialization rather than calling
functions on std::map */
int main() { }
Duplicate edit: The solution provided in that question does not work the class structure I have. I'm also looking for a solution to fix make_map_by_moving function in other words an inline initialization, the answer provided there is an imperative solution with function calls.
You cannot do this directly, because initializer_list has const backing for all of its elements - and they have to be copied from the initializer list into the container. That, obviously, requires copying. There's no way to emplace from an initializer list unfortunately.
In C++17, thanks to guaranteed copy elision, you can do this:
std::map<int, non_copyable> get() {
std::map<int, non_copyable> m;
m.emplace(std::piecewise_construct, std::tuple(0), std::tuple());
m.emplace(std::piecewise_construct, std::tuple(1), std::tuple());
return m;
}
std::map<int, non_copyable> value_classes = get();
This code performs no copies on non_copyable. We emplace construct inside of the map, and then beacuse get() is a prvalue, there is no copy/move from get() into value_classes. The m within get() is the object value_classes.
A slightly sneaker approach would be to abuse try_emplace() for this:
std::map<int, non_copyable> get() {
std::map<int, non_copyable> m;
m.try_emplace(0);
m.try_emplace(1);
return m;
}
try_emplace() takes the key type by itself (so you can just pass an int) and then the arguments for the value for emplacing separately, which makes for a much less verbose way of accomplishing this.
I think you need to create the object with insert_or_assign in a function and then return it:
std::map<int, ValueClass> populate()
{
std::map<int, ValueClass> value_classes;
value_classes.insert_or_assign(std::make_pair(0, ValueClass());
return value_classes;
}
And your initialization becomes:
std::map<int, ValueClass> value_classes = populate();
But then, this class has a virtual destructor, which means that you want actually may actually be a std::map<int, std::unique_ptr<ValueClass>> and not a map of actual objects (not sure what these objects are going to be used for?).
Edit after the question edit:
In this case, Barrys suggestion is the one to follow, usingemplace`:
std::map<int, ValueClass> populate()
{
std::map<int, ValueClass> value_classes;
value_classes.emplace(1, 5);
return value_classes;
}
Also include functional.
You simply can not use initializer_list to move an object from a non-copyable object.
Your class deletes the copy constructor & assignment operator. When you try to initialize your map or any other container with an initializer_list the initializer_list strictly forces you to reference an LValue and forbids RValue move or forward semantics.
Here is a very nice blog article that explains all of the details: knatten.org as well as a similar Q/A found here.
Recently I have read a part of "Concurrency in action" book concerning parallel quicksort implementation. I tried to check the code mentioned in the book and received an error on this part:
struct listPart
{
list<T> data;
promise<list<T>> promise;
};
listPart newLowerPart;
...
parts.push(move(newLowerPart));
The compiler gives the error
std::promise::promise(const std::promise> &) : attempting
to reference a deleted function.
The error is occured in generated copy constructor of listPart.
I guess trying to move newLowerPart it tries to use deleted copy constructor of promise. I thought creating custom copy constructor would help, but even an attempt to move promise inside it gave me the same error. Could you help me to solve this problem?
Thank you in advance
The problem is likely with your parts container implementation - it tries to copy the push parameter instead of moving it.
Here is an example:
#include <list>
#include <future>
struct listPart
{
std::list<int> data;
std::promise<std::list<int>> p;
};
template<typename T>
class dummy_container{
T t_;
public:
void push_back(const T& t){
t_ = t;
}
void move_back(const T& t){
t_ = t;
}
void move_back(T&& t){
t_ = std::move(t);
}
};
int main() {
dummy_container<listPart> dc;
listPart lp;
//dc.push_back(std::move(lp)); // won't compile, function only handles const references
dc.move_back(std::move(lp)); // will compile, because it moves if possible
}
Remember, that correct handling rvalues requires special treatment. So your container should provide at least two versions of push:
void push(const T& t); //'t' is coopied
and
void push(T&& t); //'t' is moved
Also, you should define move constructor for listPart and forbid copying:
Solution:
struct listPart
{
list<T> data;
promise<list<T>> promise;
listPart(const listPart&) = delete;
listPart(listPart&& source)
: data(std::move(source.data))
, promise(std::move(source.promise))
{ }
};
I thought creating custom copy constructor would help
As I demonstrated, you shouldn't define copy constructor for listPart - it should either be deleted or (in case of pre-C++ 11) private with no implementation provided. That's because copying std::promise is not defined (its copy constructor is deleted), so copying instance of listPart is meaningless in this case.
Ok, the question title is a bit hard to phrase. What I am trying to achieve is create a template class with get/set functions that can handle simple types and structures.
This is simple for types such as integers and char, etc... But when the template type 'T' is a struct then it gets harder.
For example, here is a template class, where I have omitted various parts of it (such as constructor, etc), but it shows the get/set function:
EDIT: Only this class is allowed to modify the data, so passing a reference outside is not allowed. The reason is that I want to do a mutex around the set/get. I will/have update the functions...
template <class T> class storage
{
private:
T m_var;
pthread_mutex_t m_mutex;
public:
void set(T value)
{
pthread_mutex_lock(&m_mutex);
m_var = value;
pthread_mutex_unlock(&m_mutex);
}
T get(void)
{
T tmp;
// Note: Can't return the value within the mutex otherwise we could get into a deadlock. So
// we have to first read the value into a temporary variable and then return that.
pthread_mutex_lock(&m_mutex);
tmp = m_var;
pthread_mutex_unlock(&m_mutex);
return tmp;
}
};
Then consider the following code:
struct shape_t
{
int numSides;
int x;
int y;
}
int main()
{
storage<int> intStore;
storage<shape_t> shapeStore;
// To set int value I can do:
intStore.set(2);
// To set shape_t value I can do:
shape_t tempShape;
tempShape.numSides = 2;
tempShape.x = 5;
tempShape.y = 4;
shapeStore.set(tempShape);
// To modify 'x' (and keep y and numSides the same) I have to do:
shape_t tempShape = shapeStore.get();
tempShape.x = 5;
shapeStore.set(tempShape);
}
What I want to be able to do, if its possible, is to set the members of shape_t individually via some means in the template class, something like:
shapeStore.set(T::numSides, 2);
shapeStore.set(T::x, 5);
shapeStore.set(T::y, 4);
And not have to use a temp var. Is this possible? how?
I looked at this answer, but it did not quite do what I wanted because it is for a specific structure type
Make your get() member return a reference:
T& get()
{
return m_var;
}
Then you could say
shapeStore.get().x = 42;
Note it is good practice to add a const overload:
const T& get() const
{
return m_var;
}
Also note that if your get and set methods really do nothing special, as in your example, you might consider making the data public and doing away with getters/setters:
template <class T> struct storage
{
T m_var;
};
Edit: If you want to allow synchronised changes to the member, an option is to have a method that takes a modifying function. The function is applied inside the class, in your case, protected by the mutex. For example,
template <class T> struct storage
{
storage() : m_var() {}
void do_stuff(std::function<void(T&)> f)
{
std::lock_guard<std::mutex> lock(m_mutex);
f(m_var);
}
private:
T m_var;
std::mutex_t m_mutex;
};
Then you can modify members in a synchronised manner:
storage<shape_t> shapeStore;
shapeStore.do_stuff([](shape_t& s)
{ s.x = 42;
s.y = 100; });
If you don't have C++11 you can pass a function instead:
void foo(shape_t& s) { s.x = 42; }
shapeStore.do_stuff(foo);
Your design is fairly workable for primitive types, but it requires you to replicate the entire interface of class types and quickly becomes unmanageable. Even in the case of primitive types, you might want to enable more complex atomic operations than simply get and set, e.g., increment or add or multiply. The key to simplifying the design is to realize that you don't actually want to interpose on every single operation the client code performs on the data object, you only need to interpose before and after the client code atomically performs a sequence of operations.
Anthony Williams wrote a great article in Doctor Dobb's Journal years ago about this exact problem using a design where the manager object provides a handle to the client code that the client uses to access the managed object. The manager interposes only on the handle creation and destruction allowing clients with a handle unfettered access to the managed object. (See the recent proposal for standardization for excruciating detail.)
You could apply the approach to your problem fairly easily. First, I'll replicate some parts of the C++11 threads library because they make it MUCH easier to write correct code in the presence of exceptions:
class mutex {
pthread_mutex_t m_mutex;
// Forbid copy/move
mutex(const mutex&); // C++11: = delete;
mutex& operator = (const mutex&); // C++11: = delete;
public:
mutex(pthread_mutex_) { pthread_mutex_init(&m_mutex, NULL); }
~mutex() { pthread_mutex_destroy(&m_mutex); }
void lock() { pthread_mutex_lock(&m_mutex); }
void unlock() { pthread_mutex_unlock(&m_mutex); }
bool try_lock() { return pthread_mutex_trylock(&m_mutex) == 0; }
};
class lock_guard {
mutex& mtx;
public:
lock_guard(mutex& mtx_) : mtx(mtx_) { mtx.lock(); }
~lock_guard() { mtx.unlock(); }
};
The class mutex wraps up a pthread_mutex_t concisely. It handles creation and destruction automatically, and saves our poor fingers some keystrokes. lock_guard is a handy RAII wrapper that automatically unlocks the mutex when it goes out of scope.
storage then becomes incredibly simple:
template <class> class handle;
template <class T> class storage
{
private:
T m_var;
mutex m_mutex;
public:
storage() : m_var() {}
storage(const T& var) : m_var(var) {}
friend class handle<T>;
};
It's simply a box with a T and a mutex inside. storage trusts the handle class to be friendly and allows it poke around its insides. It should be clear that storage does not directly provide any access to m_var, so the only way it could possibly be modified is via a handle.
handle is a bit more complex:
template <class T>
class handle {
T& m_data;
lock_guard m_lock;
public:
handle(storage<T>& s) : m_data(s.m_var), m_lock(s.m_mutex) {}
T& operator* () const {
return m_data;
}
T* operator -> () const {
return &m_data;
}
};
it keeps a reference to the data item and holds one of those handy automatic lock objects. The use of operator* and operator-> make handle objects behave like a pointer to T.
Since only way to access the object inside storage is through a handle, and a handle guarantees that the appropriate mutex is held during its lifetime, there's no way for client code to forget to lock the mutex, or to accidentally access the stored object without locking the mutex. It can't even forget to unlock the mutex, which is nice as well. Usage is simple (See it working live at Coliru):
storage<int> foo;
void example() {
{
handle<int> p(foo);
// We have exclusive access to the stored int.
*p = 42;
}
// other threads could access foo here.
{
handle<int> p(foo);
// We have exclusive access again.
*p *= 12;
// We can safely return with the mutex held,
// it will be unlocked for us in the handle destructor.
return ++*p;
}
}
You would code the program in the OP as:
struct shape_t
{
int numSides;
int x;
int y;
};
int main()
{
storage<int> intStore;
storage<shape_t> shapeStore;
// To set int value I can do:
*handle<int>(intStore) = 2;
{
// To set shape_t value I can do:
handle<shape_t> ptr(shapeStore);
ptr->numSides = 2;
ptr->x = 5;
ptr->y = 4;
}
// To modify 'x' (and keep y and numSides the same) I have to do:
handle<shape_t>(shapeStore)->x = 5;
}
I can propose you alternative solution.
When you need you can get special template class that allows managing containing object.
template < typename T >
class SafeContainer
{
public:
// Variadic template for constructor
template<typename ... ARGS>
SafeContainer(ARGS ...arguments)
: m_data(arguments ...)
{};
// RAII mutex
class Accessor
{
public:
// lock when created
Accessor(SafeContainer<T>* container)
:m_container(container)
{
m_container->m_mutex.lock();
}
// Unlock when destroyed
~Accessor()
{
m_container->m_mutex.unlock();
}
// Access methods
T* operator -> ()
{
return &m_container->m_data;
}
T& operator * ()
{
return m_container->data;
}
private:
SafeContainer<T> *m_container;
};
friend Accessor;
Accessor get()
{
return Accessor(this);
}
private:
T m_data;
// Should be using recursive mutex to avoid deadlocks
std::mutex m_mutex;
};
Example:
struct shape_t
{
int numSides;
int x;
int y;
};
int main()
{
SafeContainer<shape_t> shape;
auto shapeSafe = shape.get();
shapeSafe->numSides = 2;
shapeSafe->x = 2;
}
I am creating a class which interops with some Windows API code, now one of the pointers I have to initialize is done by calling a native function which initializes it.
My pointers are of type std::unique_ptr with a custom deleter, which calls the WinAPI deleter function provided, however I cannot pass the unique_ptr with the & address-of operator to the init-function. Why?
I have created a sample that demonstrates my problem:
#include <memory>
struct foo
{
int x;
};
struct custom_deleter {};
void init_foo(foo** init)
{
*init = new foo();
}
int main()
{
std::unique_ptr<foo, custom_deleter> foo_ptr;
init_foo(&foo_ptr);
}
The compiler barks and says:
source.cpp: In function 'int main()':
source.cpp:19:21: error: cannot convert 'std::unique_ptr<foo, custom_deleter>*' to 'foo**' for argument '1' to 'void init_foo(foo**)'
Somewhere under the covers, unique_ptr<foo> has a data member of type foo*.
However, it's not legitimate for a user of the class to directly modify that data member. Doing so would not necessarily preserve the class invariants of unique_ptr, in particular it wouldn't free the old pointer value (if any). In your special case you don't need that to happen, because the previous value is 0, but in general it should happen.
For that reason unique_ptr doesn't provide access to the data member, only to a copy of its value (via get() and operator->). You can't get a foo** out of your unique_ptr.
You could instead write:
foo *tmp;
init_foo(&tmp);
std::unique_ptr<foo, custom_deleter> foo_ptr(tmp);
This is exception-safe for the same reason that std::unique_ptr<foo, custom_deleter> foo_ptr(new foo()); is exception-safe: unique_ptr guarantees that whatever you pass in to its constructor will eventually get deleted using the deleter.
Btw, doesn't custom_deleter need an operator()(foo*)? Or have I missed something?
Steve has already explained what the technical problem is, however, the underlying problem goes much deeper: The code employs an idiom helpful when you deal with naked pointers. Why does this code do two-step initialization (first create the object, then initialize it) in the first place? Since you want to use smart pointers, I'd suggest you carefully adapt the code:
foo* init_foo()
{
return new foo();
}
int main()
{
std::unique_ptr<foo, custom_deleter> foo_ptr( init_foo() );
}
Of course, renaming init_foo() to create_foo() and having it return a std::unique_ptr<foo> directly would be better. Also, when you use two-step initialization, it's often advisable to consider using a class to wrap the data.
You can use the following trick:
template<class T>
class ptr_setter
{
public:
ptr_setter(T& Ptr): m_Ptr{Ptr} {}
~ptr_setter() { m_Ptr.reset(m_RawPtr); }
ptr_setter(const ptr_setter&) = delete;
ptr_setter& operator=(const ptr_setter&) = delete;
auto operator&() { return &m_RawPtr; }
private:
T& m_Ptr;
typename T::pointer m_RawPtr{};
};
// Macro will not be needed with C++17 class template deduction.
// If you dislike macros (as all normal people should)
// it's possible to replace it with a helper function,
// although this would make the code a little more complex.
#define ptr_setter(ptr) ptr_setter<decltype(ptr)>(ptr)
and then:
std::unique_ptr<foo, custom_deleter> foo_ptr;
init_foo(&ptr_setter(foo_ptr));
I eventually came up with an approach that allows to initialise unique_ptr's with a code like this:
struct TOpenSSLDeleter { ... }; // Your custom deleter
std::unique_ptr<EVP_MD_CTX, TOpenSSLDeleter> Ctx;
...
Ctx = MakeUnique(EVP_MD_CTX_create()); // MakeUnique() accepts raw pointer
And here is the solution:
template <class X>
struct TUniquePtrInitHelper {
TUniquePtrInitHelper(X *Raw) noexcept {
m_Raw = Raw;
}
template <class T, class D>
operator std::unique_ptr<T, D>() const noexcept {
return std::unique_ptr<T, D>(m_Raw);
}
private:
X *m_Raw;
};
template <class X>
TUniquePtrInitHelper<X> MakeUnique(X *Raw) noexcept {
return {Raw};
}