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
Related
I have a base class, and I do not want to make derived class copyable. In order to make everything explicit I implement it in that way:
class A {
public:
A() = default;
virtual ~A() = default;
A(const A&) = delete;
A(const A&&) = delete;
A& operator=(const A&) = delete;
A& operator=(const A&&) = delete;
virtual void vFun() = 0;
};
class B : public A {
public:
B() = default;
virtual ~B() = default;
B(const B&) = delete;
B(const B&&) = delete;
B& operator=(const B&) = delete;
B& operator=(const B&&) = delete;
virtual void vFun() override {}
};
Is this correct way of doing such things? According to my knowledge and what I have read, the answer is yes, but I would like to be sure before I introduce it into production system.
EDIT
Taking things into conclusion:
1) Almost always move operators should not be deleted. That's because "there's an infinity of things that require movability".
2) For abstract base class, it's safer to allow compiler to generate special member function, and move deletion into derived class if such necessity exists.
Nope, this is completely incorrect.
Firstly, in your quest to make the derived class noncopyable, you have made it non-movable, which renders it nearly useless.
Secondly, there's no reason for A to be noncopyable at all. Each derived class can just make itself noncopyable if it wants to. A is already abstract and cannot be sliced so there's no reason to make A noncopyable.
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)
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;
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);
};
This concerns the resolution of C++ Issue http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1402 . Summary:
template<typename T>
struct wrap
{
wrap() = default;
wrap(wrap&&) = default;
wrap(const wrap&) = default;
T t;
};
struct S {
S(){}
S(const S&){}
S(S&&){}
};
typedef wrap<const S> W;
// Error, defaulted move constructor of "wrap<const S>" is deleted!
W get() { return W(); }
(The issue is that we are getting an error for this snippet, even though the compiler could simply use the copy constructor of "S", as it does when the user explicitly writes the move constructor of "wrap". The issue was resolved to ignore deleted move constructors (and assignment operators) during overload resolutions, hence using the copy constructor above as desired.)
When the resolution was drafted, the following comment was made about this resolution:
There are no additional restrictions for implicit/defaulted move operations relative to copy. This means that move assignment in a virtual base is dangerous (and compilers should probably warn) [...] But we decided in Batavia that we weren't going to preserve all C++03 code against implicit move operations, and I think this resolution provides significant performance benefits.
Can someone please describe what the concern with virtual base move assignment operators is?
Consider:
#include <iostream>
struct A
{
A() = default;
A(const A&) = default;
A(A&&) = default;
A& operator=(const A&) {std::cout << "operator=(const A&)\n"; return *this;}
A& operator=(A&&) {std::cout << "operator=(A&&)\n"; return *this;}
};
struct B
: virtual public A
{
};
struct C
: virtual public A
{
};
struct D
: public B,
public C
{
};
int
main()
{
D d1, d2;
d1 = std::move(d2);
}
I believe this program should output:
operator=(A&&)
operator=(A&&)
For me it actually outputs:
operator=(const A&)
operator=(const A&)
But I think this is just a clang bug (compiled with -std=c++1y). If I am correct about what the output should be, then the danger is that the move assignment operator is called twice. This is harmless (though potentially expensive) with the copy assignment operator, but not with the move assignment operator.