Is there a way to disable operator= and copy constructor and allow using std::move() only?
I know that i can do
foo& operator= (const foo&) = delete;
foo(const foo&) = delete;
but this will disable std::move too.
What i want is to block copying of this class
and allow only foo foo2 = std::move(foo1);
Btw. I have private contructor.
Use defaulted special member functions:
foo(foo&&) = default;
foo& operator=(foo&&) = default;
Related
I have a class with deleted copy constructors and I'm trying to put a mutex member in something like this:
struct A {
A(const A &other) = delete;
A& operator=(const A &other) = delete;
A(A&& other) = default;
A& operator=(A &&other) = default;
std::mutex lock;
};
The compiler is complaining that I'm trying to call the deleted copy constructor, which I summarise to be due to the std::mutex type being non-movable. How can I make the mutex member play with the move constructors with minimal fuss? I don't actually want to move the mutex member itself into the newly constructed object, and would actually like each moved object to just construct it's own mutex
I don't actually want to move the mutex member itself into the newly constructed object, and would actually like each moved object to just construct it's own mutex
Then simply define your move constructor to construct a new mutex:
struct A {
A(const A &other) = delete;
A& operator=(const A &other) = delete;
A(A&& other)
: lock()
{
}
A& operator=(A &&other) = delete;
std::mutex lock;
};
Move assignment will still be a problem and should probably just be deleted. Unless you can answer the question: what happens to the existing mutex member when you're being assigned a new value? Particularly: what if you are assigned a new value while the existing mutex is locked?
As an alternative to providing custom move operations for your class, you could create a generic wrapper:
template <class T>
class PerObject
{
T data;
public:
PerObject() = default;
PerObject(const PerObject&) {}
PerObject& operator= (const PerObject&) { return *this; }
T& operator* () const { return data; }
T* operator-> () const { return &data; }
};
And use it like this:
struct A {
A(const A &other) = delete;
A& operator=(const A &other) = delete;
A(A&& other) = default;
A& operator=(A &&other) = default;
PerObject<std::mutex> lock;
};
The wrapper's copy (and move) operations are no-ops, so the object containing the wrapper will always contain the one it started with.
Caveat: However, based on how your class uses the mutex, the above could actually be dangerous. If the mutex is used to protect other data within the class, then it should likely be locked while the object is being assigned to, so you will have to provide manual move operations anyway. In such case, the code would likely look something like this:
struct A {
A(A&& other) : lock{}, /* anything else you need to move-construct */
{
// Note: it might even be necessary to lock `other.lock` before moving from it, depending on your class's exact semantics and expected use.
}
A& operator=(A &&other)
{
if (this == &other) return *this; // Otherwise, double-locking would be possible
// If you need to lock only this object:
std::unique_lock<std::mutex> l(lock);
// Alternatively, if you need to lock both objects:
std::scoped_lock l(lock, other.lock);
// Now move data from other to this
return *this;
}
std::mutex lock;
};
One way is to make your move constructor to create new mutex when called.
A(A&& other): lock()
{
//... move other things
}
You can also use a std::unique_ptr() to the std::mutex since it is movable.
struct A {
A(const A &other) = delete;
A& operator=(const A &other) = delete;
A(A&& other) = default;
A& operator=(A &&other) = default;
std::unique_ptr<std::mutex> lock;
};
A::A() : lock(new std::mutex())
With this approach you'll not create new mutex each time you move the object which will remove some of the overhead.
To disable copy constructor and assignment operator, it is clear that we could do either, since c++11:
class A {
public:
A(const A&) = delete;
A& operator=(const A&) = delete;
}
or for c++03:
class A {
private:
A(const A&);
A& operator=(const A&);
}
however, what happens with this:
class A {
private:
A(const A&) = delete;
A& operator=(const A&) = delete;
}
i guess this also leads to the same result. Is there any side effect?
It doesn't matter what access you give a deleted function - it simply doesn't exist(¹), so it is inaccessible whatever the caller.
The error messages may be slightly more confusing. See for example http:://cpp.sh/9hv7y where the first error is about "private" rather than "deleted".
¹ "it doesn't exist" is a simplification. It exists in the sense that it participates in overload resolution, but it is an error if it is the selected function. Thus
struct only_double {
only_double(intmax_t) = delete;
only_double(double arg);
};
only_double zero(0); // Error - deleted constructor called
If I want to forbid copy construction/assignment then is:
class foo
{
public:
foo(const foo&) = delete;
foo& operator = (const foo&) = delete;
};
The same as:
class foo
{
private:
foo(const foo&) = default;
foo& operator = (const foo&) = default;
};
Which is the right way and why?
The right way is the first solution : the copy constructor and assignment operators are not defined, so any attempt to use them will not compile.
class foo
{
public:
foo(const foo&) = delete;
foo& operator = (const foo&) = delete;
};
The second is declaring and defining the implicitly generated forms as private :
An object of type foo is allowed to copy itself.
Any friend class or method is also allowed to copy a foo
So copy construction/assignment is still possible.
You could also use boost::noncopyable as a base class, it does exactly that with c++11 (see the source code here)
How can I make a Class non-cloneable like we can do in Java while creating singleton.
Is there any condition we can put on copy constructor so that an exception can be thrown if user tries to make a copy of an object?
I am a novice in C++ so kindly add any info to this or redirect if an answer is already available for the same.
Just declare copy constructor and copy assign operator private
in C++03
class NonCopyable
{
public:
NonCopyable() { }
private:
NonCopyable(const NonCopyable&);
NonCopyable& operator=(const NonCopyable&);
};
Also you can make a class derive from NonCopyable, AnotherType is un-copyable
class AnotherNonCopyable : private NonCopyable
{
public:
AnotherNonCopyable () {}
}
With C++11:
class NonCopyableType
{
public:
NonCopyableType(const NonCopyableType&) = delete;
NonCopyableType& operator=(const NonCopyableType&) = delete;
};
You can delete the copy constructor and assignment operator:
struct Foo
{
Foo(const& Foo) = delete;
Foo& operator=(const Foo&) = delete;
};
If you don't have C++11 support, make them private, and don't implement them:
struct Foo
{
private:
Foo(const& Foo);
Foo& operator=(const Foo&);
};
Note In C++, class and struct are essentially the same.
Declare the copy-semantics as delete:
//C++11 only
MyClass(MyClass const &) = delete;
MyClass& operator=(MyClass const &) = delete;
That makes the class non-copyable!
//pre-C++11 code
private:
MyClass(MyClass const &); //declare only, don't define it
MyClass& operator=(MyClass const &); //declare only, don't define it
This should also work!
Is there any condition we can put on copy constructor so that an
exception can be thrown if user tries to make a copy of an object.
if you make the copy constructor private, The code will not compile when the programmer tries to make another copy. This is probably better than detecting the error with an exception at runtime.
class foo {
private:
operator = ( const foo& f);
};
Given the following code (http://liveworkspace.org/code/5oact):
class Foo
{
public:
Foo()
{
log(__PRETTY_FUNCTION__);
}
Foo(const Foo& other)
{
log(__PRETTY_FUNCTION__);
}
Foo& operator=(const Foo& other)
{
log(__PRETTY_FUNCTION__);
return *this;
}
Foo(Foo&& other) noexcept
{
log(__PRETTY_FUNCTION__);
}
Foo& operator=(Foo&& other) noexcept
{
log(__PRETTY_FUNCTION__);
return *this;
}
~Foo(){}
};
Using the class like this:
std::vector<Foo> tt;
tt.emplace_back();
tt.emplace_back();
tt.emplace_back();
tt.emplace_back();
I get the following output:
Foo::Foo()
Foo::Foo()
Foo::Foo(const Foo&)
Foo::Foo()
Foo::Foo(const Foo&)
Foo::Foo(const Foo&)
Foo::Foo()
and if I remove the custom destructor I get the following output:
Foo::Foo()
Foo::Foo()
Foo::Foo(Foo&&)
Foo::Foo()
Foo::Foo(Foo&&)
Foo::Foo(Foo&&)
Foo::Foo()
Why the compiler uses the copy constructor instead of the move when I declare a destructor? I understand that the move operation can't throw (and if I remove the noexcept from the code, the compiler won't use it at all), but what the destructor has to do with that?
First, it seems that there is an issue with your compiler that uses the wrong noexcept specification. According to the standard, 12.4.3:
A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration
An implicit declaration of a destructor would be noexcept if all the members and bases' destructors are noexcept as well. So your explicit destructor declaration should be equivalent to:
~Foo() noexcept {} // or:
~Foo() noexcept(true) {}
but instead your compiler is treating it as:
~Foo() noexcept(false) {}
Second, the reason the exception-specification of a destructor affects the decision on whether to move or not is because destruction is involved in the operation. Just as noexcept on a move-constructor and a move-assignment operation affect the decision, move won't be used if there is a possibility that an exception might be thrown mid-process.