boost::shared_ptr boost::mutex and copy constructor - c++

I need to protect the access to a data structure in my class. As I can't have mutex (because I can't copy it) I am considering to have shared_ptr and keep the mutex there. Here is a sample code of my idea:
class Sample {
typedef boost::lock_guard<boost::mutex> AcquireLock;
boost::shared_ptr<boost::mutex> mutt;
public:
Sample() : mutt(new boost::mutex) {}
void Method()
{
AcquireLock lock(*mutt);
//do some work here
}
};
I've got the following questions:
Is it a bad practice to use the mutex that way (as member of the class, via shared_ptr)?
Should I have copy constructor for this class, as it has memory allocated on heap via shared_ptr?
EDIT: Maybe I need to give a bit more details:
I'll create this object only once and save it in std::vector. I don't need to make copies of it and if the vector needs to make copies, I don't want to have different mutex for each copy. That's why I think the copy constructor will work for me.

This approach is pretty valid and legitimate, but note that as your class evolves, you might want to apply the same technique to some more class members. That's why I'd recommend you to consider taking an advantage of pImpl idiom:
// in hpp:
class Sample
{
Impl();
private:
struct Impl;
// compiler generated copy-constructor will copy only this shared_ptr
shared_ptr<void> pImpl_;
};
// in cpp:
struct Sample::Impl
{
mutex mut_;
// put here whatever members you need, extend Impl without affecting the Sample interface
};
Impl::Impl() : pImpl_(new Impl)
{}

If you make a copy of a Sample object, the copy constructor will be called, either one generated automatically by the compiler, or one that you have written explicitly.
Whether it's a good idea to allow copies of Sample objects depends on what you are trying to do.
If it doesn't make sense to allow copies, then make the object non-copyable, e.g. by giving a private prototype for the copy constructor.
If you do want to allow copies, then you need to decide if each copy should have its own mutex, and define the copy constuctor appropriately. The automatically generated copy constructor will only do a shallow copy, so all copies would share the mutex.

Related

Unique Pointers and The Rule of 3

I often find myself using unique pointers in C++ when I want polymorphic behaviour. I typically implement pure abstract classes something like the below:
class A {
public:
virtual A* clone() const = 0; // returns a pointer to a deep copy of A
// other methods go here
};
The clone method comes in handy when I want to embellish another class with its own instance of A, for example:
#include <memory>
class B {
private:
std::unique_ptr<A> a_ptr;
public:
// ctor
B(const A& a) {
a_ptr = std::unique_ptr<A>(a.clone());
//...
}
// copy ctor
B(const B& other) : B(*other.a_ptr) {}
};
I invariably end up implementing the copy constructor in B to avoid a compiler error (MSVC gives a vague message about attempting to reference a deleted function), which makes complete sense because of the unique pointer. My questions can be summarised as follows:
Do I actually need the copy constructor in B? Perhaps there's a better pattern that would allow me to avoid it altogether.
If yes to 1, can I stop there? Will I ever need to implement the other default functions? I.e. is there any scenario where I need a default constructor and destructor also?
In practice, whenever I feel I need to implement the default functions, I typically implement a move-constructor alongside the other three; I usually use the copy-and-swap-idiom (as per GManNickG's answer in this thread). I assume this wouldn't change anything, but maybe I am wrong!
Thanks a lot!
First, I think the signature of your clone function could be
virtual std::unique_ptr<A> clone() = 0;
as you want deep copies of A instances and exclusive ownership within B. Second, you indeed have to define a copy constructor for your class when you want it to be copyable. Same for an assignment operator. This is due to the fact that std::unique_ptr is a move-only type, which hinders the compiler to generate default implementations.
Other special member functions are not needed, though they might make sense. The compiler won't generate move constructor and move assignment operator for you (as you ship your own copy/assignment functions), though in your case, you can = default; them easily. The destructor can equally well be defined with = default;, which would be in line with the core guidelines.
Note that defining the destructor via = default should be done in a translation unit, as std::unique_ptr requires the full type do be known upon freeing its resource.
Whether you need a default constructor totally depends on how yo want to use the class B.
As #lubgr mentioned in his answer, You should return unique_ptr not a raw one from the clone function. Anyway, going to Your questions:
Do You need a copy constructor in B? Well it depends on Your use cases, but if You copy objects of class B You may need one. But as You said, You do it quite often, so it would be wise to consider more generic approach. One of these would be creating a wrapper for unique_ptr which would have copy constructor and which would make a deep copy of this pointer in this copy constructor.
Consider following example:
template<class T>
class unique_ptr_wrap {
public:
unique_ptr_wrap(std::unique_ptr< T > _ptr) : m_ptr(std::move(_ptr)){}
unique_ptr_wrap(const unique_ptr_wrap &_wrap){
m_ptr = _wrap->clone();
}
unique_ptr_wrap(unique_ptr_wrap &&_wrap){
m_ptr = std::move(_wrap.m_ptr);
}
T *operator->() const {
return m_ptr.get();
}
T &operator*() const {
return *m_ptr;
}
private:
std::unique_ptr< T > m_ptr;
};
This again depends on Your needs. I personally would recommend overloading move constructor as well, to make it use less dynamic allocations (but this may be premateure optimization which is root of all evil).

Adding a move only type to a class makes that class as a move only type?

In Scott Meyers' "Effective Modern C++", he writes:
It's worth nothing that because std::mutex is a move-only type (i.e., a type that can be
moved, but not copied), a side effect of adding m to Polynomial is that Polynomial loses the ability to be copied. It can still be moved, however.
Here, he adds a std::mutex m as a member variable to a class Polynomial in the context of explaining why one should protect access to const member variable of a class(while multi-threading). I understood the concept he explained. but one thing which I need to have some more explanation is "why Adding a move only type to a class makes that class as move only type not copy-able"?, why types like std::mutex and std::atomic is move only type by default? how can we get over with it if we want to perform copy operation even when adding move only type of variable to our class?
"why Adding a move only type to a class makes that class as move only type not copy-able"
This is not entierly true. adding non copyable member variable prevents you from writing something like Type (const Type& t) = default; , but you can still implement you own copy constructor which ignores the non copyable member
class Type{
int integer;
std::mutex m;
public:
Type() = default;
Type(const Type& rhs): integer (rhs.integer){}
}
Other than this, you can find numerous examples of objects that contain move-only members, but they are themselves non movable, simply because the developer deleted the move constructor.
why types like std::mutex and std::atomic is move only type by default?
Neither of them implement move constructor. this is a wrong statement.
std::mutex is not copyable only because the standard says so. They could probably have written a std::mutex that was copyable, but they decided not to.
As a guess, a non-copyable std::mutex might be more efficient, safer, or easier to understand.
As an example, here is why it might be safer/easier to understand: What does it mean to copy a std::mutex that is locked? I, personally, have no idea what the right answer is; I suspect that the right answer is "that is nonsense". There is no "answer of least surprise".
Instead of having a surprising answer in concurrency code, by blocking copy we avoid the question. People storing a mutex who want to copy have to decide themselves what they want it to do.
C++ will under some circumstances automatically generate a copy constructor. Under more circumstances it will let you do MyClass(MyClass const&)=default and write one when you ask for it.
If your class contains a non-copyable class, it won't generate one, and you cannot ask for it. This is because the generated copy constructor basically copies its members; if you cannot copy a member, it cannot generate a copy constructor.
So mutex cannot be copied because the standard says so.
If a struct or class contains a non-copyable member, the default copy constructor cannot be used. You have to write one yourself explicitly.
If your type needs to store a mutex, one approach to prevent the headache of having to maintain a copy ctor that manually copies all of its other members is to stick your non-mutex state into a sub-struct, and then use its default copy. Then you decide what to do with the mutex during the copy, and your copy ctor (and assignment copy operator) remain simple.
struct bob_with_mutex {
sturct bob_simple_data {
int x, y, z;
std::vector<char> buff;
};
bob_simple_data data;
std::mutex m;
bob_with_mutex( bob_with_mutex const& o ):
data(o.data)
{}
bob_with_mutex& operator=( bob_with_mutex const& o )
{
data = o.data;
return *this;
}
};
the type bob has a mixture of a mutex and some data. The data is stored in a sub-structure. The copy ctor of bob_with_mutex cannot be defaulted, but it simply says "copy the data, and nothing else".
The copy of the bob has its own mutex.
One possibility is to change the mutex type to a pointer to a mutex. You can copy the pointer, but there will still only be one copy of the mutex. You may want to use a smart pointer.

Error while declaring a class with std::vector of structs containing std::unique_ptr

Although having worked several years with C#, getting things done in C++ is sometime still difficult for me. I fully embrace the usage of smart pointers, but now I'm facing the following puzzle
I have a struct Foo, e.g.
struct Foo
{
Foo(std::unique_ptr<Bar> bar) : m_myBar(std::move(bar)) {}
private:
std::unique_ptr<Bar> m_myBar;
};
In a different class, I want to have a vector containing instances of Foo, but the following line
std::vector<Foo> m_Foos;
yields compile errors saying that the copy constructor is deleted. In the SO thread "Why can I not push_back a unique_ptr into a vector?" an explanation as well as a remedy is given. However, there the question concerns a vector of unique pointers whereas I have a vector of structs containing a unique pointer. The suggested solution is to use move semantics, but how does that apply in my situation? Or should I be doing something else?
As you say, m_Foos is actually a data member of another class (I'll call it FooHolder). If you didn't provide a copy constructor for FooHolder, the compiler will generate one automatically. That copy constructor will call the copy constructors of all data members of FooHolder, including m_Foos. Of course, the copy constructor of std::vector<Foo> contains a compilation error, since Foo is not copyable. This is probably why you're getting the error.
You'll have to provide an appropriate copy constructor for FooHolder, if you are able to and want that class to be copyable. Otherwise, you can just declare a move constructor (possibly defaulted), which will make the copy constructor deleted:
struct FooHolder
{
FooHolder(FooHolder&&) = default;
private:
std::vector<Foo> m_Foos;
};
You cannot copy unique pointers. You can only move them:
Foo(std::unique_ptr<Bar> bar) : m_myBar(std::move(bar)) {}
// ^^^^^^^^^^^^^^

Is this hideous? Copyable mutex to protect class member

I'm trying to make a class thread safe by using a mutex.
class Container
{
private:
vector<Foo> v;
boost::mutex m;
public:
void add(Foo item)
{
m.lock();
v.push_back(item);
m.unlock();
}
};
The problem is that boost::mutex is non-copyable, so this makes Container noncopyable. Of course if I copy Container the new instance presumably doesn't need to keep the same mutex as the old one - it can have a new mutex of its own. I could write custom copy constructors for Container that do this but in reality it's a complex class and I don't want to. So how about this:
class CopyableMutex
{
private:
boost::mutex m;
public:
CopyableMutex() {}
CopyableMutex(CopyableMutex&) {} //don't copy, just create a new one
CopyableMutex& operator=(CopyableMutex&) {return *this;} //don't assign, keep it the same
void lock() {m.lock();}
void unlock() {m.unlock();}
};
...and then replacing boost::mutex in Container with CopyableMutex.
Is this a hideous thing to do? If not then am I reinventing the wheel - is there a library class that does this already?
Yes it's hideous.
The correct solution to the problem is a custom copy constructor and assignment operator for your container.
If the class is "too complex" to write a custom copy constructor for, then separate the thread-safety from the container and have base class container which doesn't contain a mutex and, perhaps, a derived class "thread safe container" which contains a mutex and has a custom copy constructor and assignment op that just call through to the automatically generated base class ones.
I believe that one of the things that doing it this way invalidates is the correct way to use mutexes these days:
void func()
{
std::lock_guard<std::mutex> lock(mtx);
// do things
}
As you can not return a mutex and so there would be no way to up-scope it to where you want to use it. The reason for the above style of usage is to prevent issues that arise when you use a lock, and then some form of unhanded exception happens prior to you unlock (ie it ensures a more reliable unlock).
I agree with other answer though, that a better way would be to just encapsulate your thread safety part and isolate it from your complex code (if possible), and then just make explicit copy constructors for that smaller class.

How to deal with noncopyable objects when inserting to containers in C++

I'm looking for the best-practice of dealing with non-copyable objects.
I have a mutex class, that obviously should not be copyable.
I added a private copy constructor to enforce that.
That broke the code - some places simply needed to be fixed, but I have a generic problem
where a class, using the mutex either as a data member, or by inheritance, is being inserted into a container.
This is usually happening during the container initialization, so the mutex is not initialized yet, and is therefore ok, but without a copy constructor it does not work. Changing the containers to contain pointers is not acceptable.
Any advise?
Three solutions here:
1. Use Pointers - The quick fix is to make it a container of pointers - e.g. a shared_ptr.
That would be the "good" solution if your objects are truly noncopyable, and using other containers is not possible.
2. Other containers - Alternatively, you could use non-copying containers (that use in-place-construction), however they aren't very common and largely incompatible with STL. (I've tried for a while, but it's simply no good)
That would be the "god" solution if your objects are truly noncopyable, and using pointers is not possible.
[edit] With C++13, std::vector allows inplace construction (emplace_back), and can be used for noncopyable objects that do implement move semantics.
[/edit]
3. Fix your copyability - If your class is copyable as such, and the mutex is not, you "simply" need to fix the copy constructor and assignment operator.
Writing them is a pain, since you usually have to copy & assign all members except the mutex, but that can often be simplified by:
template <typename TNonCopyable>
struct NeverCopy : public T
{
NeverCopy() {}
NeverCopy(T const & rhs) {}
NeverCopy<T> & operator=(T const & rhs) { return *this; }
}
And changing you mutex member to
NeverCopy<Mutex> m_mutex;
Unfortunately, using that template you lose special constructors of Mutex.
[edit] Warning: "Fixing" the Copy CTor/asignment often requires you to lock the right hand side on copy construct, and lock both sides on assignment. Unfortunately, there is no way to override the copy ctor/assignment and call the default implementation, so the NeverCopy trick might not work for you without external locking. (There are some other workarounds with their own limitations.)
If they are non-copyable, the container has to store (smart) pointers to those objects, or reference wrappers, etc, although with C++0x, noncopyable objects can still be movable (like boost threads), so that they can be stored in containers as-is.
to give examples: reference wrapper (aka boost::ref, a pointer under the hood)
#include <vector>
#include <tr1/functional>
struct Noncopy {
private:
Noncopy(const Noncopy&) {}
public:
Noncopy() {}
};
int main()
{
std::vector<std::tr1::reference_wrapper<Noncopy> > v;
Noncopy m;
v.push_back(std::tr1::reference_wrapper<Noncopy>(m));
}
C++0x, tested with gcc:
#include <vector>
struct Movable {
private:
Movable(const Movable&) = delete;
public:
Movable() {}
Movable(Movable&&) {}
};
int main()
{
std::vector<Movable> v;
Movable m;
v.emplace_back(std::move(m));
}
EDIT: Nevermind, C++0x FCD says, under 30.4.1/3,
A Mutex type shall not be copyable nor movable.
So you're better off with pointers to them. Smart or otherwise wrapped as necessary.
If an object is non-copyable then there is usually a good reason. And if there's a good reason then you shouldnt subvert that by putting it into a container that attempts to copy it.
There is no real answer to the question given how you've framed it. There is no way to do what you want. The actual answer is for the container to contain pointers, and you've said that isn't OK for some unspecified reason.
Some have talked about things being movable and using C++0x in which containers often require their elements to be movable, but do not require them to be copyable. I think this is a poor solution as well because I suspect that mutexes should not be moved while they are held, and this makes it effectively impossible to move them.
So, the only real remaining answer is to point at the mutexes. Use ::std::tr1::shared_ptr (in #include <tr1/memory>) or ::boost::shared_ptr to point at the mutexes. This requires changing the definitions of the classes that have the mutexes inside them, but it sounds like you're doing that anyway.
STL containers rely heavily on their contents being copyable, so either make them copyable or do not put them into container.
The best option is to use pointers or some type of wrapper class that uses pointers under the hood. That would allow these to be sanely copied, and actually do what a copy would be expected to do (share the mutex).
But, since you said no pointers, there is one other option. It sounds like Mutexes are "sometimes copyable" perhaps you should write a copy constructor and an assignment operator and have those throw an exception if a mutex is ever copied after it has been initialized. The down side is there's no way to know you're doing it wrong until runtime.
Use smart pointers like boost::shared_ptr or use another containers, like boost::intrusive. Both will require to modify your code, through.
Using a mutex in a class does not necessarily mean that the class has to be non-copyable. You can (almost) always implement it like this:
C::C (C const & c)
// No ctor-initializer here.
{
MutexLock guard (c.mutex);
// Do the copy-construction here.
x = c.x;
}
While this makes it somewhat possible to copy classes with mutexes, you probably should not do it. Chances are that your design will be better without per-instance mutex.
Using c++11 on Ubuntu 14.04 (which includes emplace_back), I've gotten this to work.
I found that emplace_back worked fine, but erase (and probably insert) didn't work because, when the vector was shuffling the elements along to fill in the gap, it mas using:
*previous = *current;
I found the trick was allowing move assignment in my resource class:
Watch& operator=(Watch &&other);
This is my inotify_watch class, which can live in a std::vector:
class Watch {
private:
int inotify_handle = 0;
int handle = -1;
// Erases all knowledge of our resources
void erase() {
inotify_handle = 0;
handle = -1;
}
public:
Watch(int inotify_handle, const char *path, uint32_t mask)
: inotify_handle(inotify_handle),
handle(inotify_add_watch(inotify_handle, path, mask)) {
if (handle == -1)
throw std::system_error(errno, std::system_category());
}
Watch(const Watch& other) = delete; // Can't copy it, it's a real resource
// Move is fine
Watch(Watch &&other)
: inotify_handle(other.inotify_handle), handle(other.handle) {
other.erase(); // Make the other one forget about our resources, so that
// when the destructor is called, it won't try to free them,
// as we own them now
}
// Move assignment is fine
Watch &operator=(Watch &&other) {
inotify_handle = other.inotify_handle;
handle = other.handle;
other.erase(); // Make the other one forget about our resources, so that
// when the destructor is called, it won't try to free them,
// as we own them now
return *this;
}
bool operator ==(const Watch& other) {
return (inotify_handle == other.inotify_handle) && (handle == other.handle);
}
~Watch() {
if (handle != -1) {
int result = inotify_rm_watch(inotify_handle, handle);
if (result == -1)
throw std::system_error(errno, std::system_category());
}
}
};
std::vector can not store non-copyable objects (due to resize) thus you can't store objects of type Foo:
struct Foo {
std::mutex mutex;
...
};
One way around this is to use std::unique_ptr:
struct Foo {
std::unique_ptr<std::mutex> pmutex;
Foo() : pmutex{std::make_unique<std::mutex>()} {}
...
};
Another option is to use a std::deque which can hold non-copyable objects (like instances of the first version of Foo above. Typically use emplace_back method to construct objects "in place" to add elements -- no copies happen. For example,
objects of type Foo here do not need to be copiable:
struct FooPool {
std::deque<Foo> objects;
ObjectPool(std::initializer_list<T> argList) {
for (auto&& arg : argList)
objects.emplace_back(arg);
...
};