I want to create a base class both noncopyable and nonmovable.
class noncopyable {
protected:
noncopyable() = default;
~noncopyable() = default;
noncopyable(noncopyable const &) = delete;
noncopyable &operator=(noncopyable const &) = delete;
};
class nonmovable {
protected:
nonmovable() = default;
~nonmovable() = default;
nonmovable(nonmovable &&) = delete;
nonmovable &operator=(nonmovable &&) = delete;
};
Is there any scenario that a class should be both noncopyable and nonmovable?
class non : public noncopyable, public nonmovable {
};
class foo : public non {
};
If there, what should be the convenient name for the "non" class here?
It has been argued, for instance here, that nonmoveable as demonstrated is a bad idea in the first place.
There are four reasonable options:
Type is naturally copyable and moveable.
Type is non-copyable, but moveable.
This happens often if it is managing a resource, and copying the resource is impossible, or so expensive as to be undesirable.
Type has no special moveability -- move ctor simply calls copy ctor.
This mostly happens if for technical reasons, you don't want to create an "empty state" for objects of this type, or there is no cheap / natural way to leave the moved-from object in any acceptable state.
Type is neither copyable nor moveable.
This may happen with a static singleton or something like this, where moving or copying it is something that should never happen in your program and you want to prevent from happening with a compile-time error.
If the type is copyable, but moving it fails, this is strictly a bad arrangement, and instead move should be made to fallback to copy. There's no advantage to making a move fail when a copy would be okay, it only inhibits generic programming.
So maybe you should only have "noncopyable" and "non", but not "nonmoveable" ?
While a "noncopyable" will work, an "nonmovable" base class will not provide what you expect:
#include <utility>
#include <iostream>
struct nonmovable
{
nonmovable() = default;
nonmovable(const nonmovable&) { std::cout << "copy\n"; }
nonmovable& operator = (const nonmovable&) { std::cout << "asign\n"; return *this; }
nonmovable(nonmovable&&) = delete;
nonmovable& operator = (nonmovable&&) = delete;
};
struct X : nonmovable {};
int main()
{
nonmovable n0;
nonmovable n1(n0);
// error: use of deleted function ‘nonmovable::nonmovable(nonmovable&&)’:
//nonmovable n2(std::move(n0));
X x0;
X x1(x0);
// However, X has a copy constructor not applying a move.
X x2(std::move(x0));
}
In addition, move construction and move assignment must be enabled explicitly after deletion of the copy constructor, if desiered:
struct noncopyable
{
noncopyable() = default;
// Deletion of copy constructor and copy assignment makes the class
// non-movable, too.
noncopyable(const noncopyable&) = delete;
noncopyable& operator = (const noncopyable&) = delete;
// Move construction and move assignment must be enabled explicitly, if desiered.
noncopyable(noncopyable&&) = default;
noncopyable& operator = (noncopyable&&) = default;
};
The, names "noncopyable" and "nonmovable" itself are good descriptive names. However, "boost::noncopyable" is both (non copyable and non movable), which might be a better (historical) design decision.
as an example - signleton pattern. Also, if u defined copy-constructor/assignment operator/destructor, move-constructor/assignment wont be generated.
Related
Let's say I want to create some classes to manage resources that shouldn't be copied nor moved, which would be the minimal class to extend and avoid mistakes?
The idea is that by extending the class, I end on the safe side of the 0/3/5 rules.
I have this in mind, which apparently works.
class NOCOPYNOMOVE {
NOCOPYNOMOVE(NOCOPYNOMOVE &v) = delete;
NOCOPYNOMOVE(NOCOPYNOMOVE &&v) = delete;
NOCOPYNOMOVE& operator=(NOCOPYNOMOVE &r) = delete;
NOCOPYNOMOVE& operator=(NOCOPYNOMOVE &&r) = delete;
};
class Foo: private NOCOPYNOMOVE {
public:
Foo() {}
~Foo() {}
};
Don't need to delete move constructor, see https://stackoverflow.com/a/38820178/2945027
Avoid ALL_CAPS name, as it is conventionally by every convention used for macros
There's no reason to omit const in copy constructor/assignment, so the usual form should be preferred
If classes would inherit from some NOCOPYNOMOVE in some namespace, it may trigger unintended ADL. boost::noncopyable solves it by putting the definition in noncopyable_ namespace, see the implementation
I'd prefer just not having some base, instead spelling out these two or three lines in the target class:
class Foo {
public:
Foo() {}
~Foo() {}
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
};
C++ compiler in certain conditions for class adds implicit default constructor, copy constructor, destructor, conversion operators, assignment operators, etc. And other implicit methods.
How do I disable/delete all possible implicit methods in shortest way possible?
I don't want my class to be un-copyable, I want just these default methods to be disabled so that compiler throws compile error and I implement them by myself. I just want to have over-control, so that compiler doesn't do any silent work about my class.
For example I can do next thing (this is just a dummy example, in real life I can have any complex class):
class C {
private:
C() = delete;
C(C const & other) = delete;
C & operator = (C const & other) = delete;
};
But this is long way, also I can forget deleting some of methods signatures and I need to delete all of them. So that I reimplement all methods from scratch by myself.
And I need to see errors for all methods that other code needs/uses and that I have not yet implemented, instead of compiler silently implementing those methods for me.
Also if I delete default methods like I did above in my example, how can I be sure that there are no other silently created methods? Is there online a list of 100% all standard methods created silently by compiler?
You may go for a mixin approach. Define the cumbersome class once
class DeleteAllSpecialMemebers {
private:
DeleteAllSpecialMemebers() = delete;
DeleteAllSpecialMemebers(DeleteAllSpecialMemebers const &) = delete;
DeleteAllSpecialMemebers & operator = (DeleteAllSpecialMemebers const &) = delete;
DeleteAllSpecialMemebers(DeleteAllSpecialMemebers &&) = delete;
DeleteAllSpecialMemebers & operator = (DeleteAllSpecialMemebers &&) = delete;
protected:
struct token { explicit token() = default; };
DeleteAllSpecialMemebers(token) {}
};
Then inherit from it:
class C : private DeleteAllSpecialMemebers{
public:
C(int) : DeleteAllSpecialMemebers(token{}) {}
};
The extra token type is to allow deriving classes to implement other constructors, such as C::C(int) (or even a user-provided C::C()).
See it live.
The shortest option might be to have a reusable dummy base class:
struct NoSpecialMember {
NoSpecialMember(const NoSpecialMember&) = delete;
NoSpecialMember& operator=(const NoSpecialMember&) = delete;
NoSpecialMember(NoSpecialMember&&) = delete;
NoSpecialMember& operator=(NoSpecialMember&&) = delete;
~NoSpecialMember() = default;
};
It's sufficient to inherit privately;
class Test : private NoSpecialMember {};
with the following result:
static_assert(!std::is_copy_constructible_v<Test>);
static_assert(!std::is_copy_assignable_v<Test>);
static_assert(!std::is_move_constructible_v<Test>);
static_assert(!std::is_move_assignable_v<Test>);
Define helper and use it as field of class where it should be disabled:
struct DisableCopyAssign
{
DisableCopyAssign(char){}
DisableCopyAssign(const DisableCopyAssign&) = delete;
DisableCopyAssign(DisableCopyAssign&&) = delete;
};
class Foo
{
private:
DisableCopyAssign dummy;
};
https://gcc.godbolt.org/z/ce8sjq
I have an abstract class with deleted copy constructor and copy assignment operator that is meant to be used as a public interface:
struct connection {
// Make object non copyable.
connection(const connection &) = delete;
auto operator=(const connection &) -> connection & = delete;
// Make class abstract.
virtual ~connection() = 0;
};
I'm trying to create a class that inherits from it:
struct abstract_connection : connection {...};
but I get the following error in the constructor:
constructor for 'abstract_connection' must explicitly initialize the base class 'connection' which does not have a default constructor
Why does this happen when I delete the copy constructor and operator?
According to the standard:
[class.default.ctor#1]
[...] If there is no user-declared constructor for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted ([dcl.fct.def]). [..]
Since you have user-declared the copy-constructor by deleting it, you need to user-provide the default constructor:
struct connection {
connection(const connection &) = delete;
auto operator=(const connection &) -> connection & = delete;
virtual ~connection() = 0;
protected: // You likely want to make it protected.
connection() = default;
};
The rules behind the automatic generation of special member functions are clearly explained in Effective Modern C++ by Scott Meyers, Item 17, p.109.
In a nutshell, whenever you redefine/override a constructor, then you need to define all the needed constructors. Since you have deleted the copy constructor, you need to define the default constructor of the base class. This is becaue you are using the default constructor when you define your derived class.
This code struct abstract_connection : connection {...}; (without any given information) means that you are most likely to initialise the abstract_connection using the default ctor from connection. But the default ctor from connection is not defined.
Furthermore, you need to define your dtor, even thought it is a virtual function. The code below compiles and runs here.
struct connection
{
connection() = default;
connection(const connection &) = delete;
auto operator=(const connection &) -> connection & = delete;
virtual ~connection() = 0;
};
connection::~connection()
{}
struct abstract_connection : connection
{
abstract_connection() : connection()
{}
~abstract_connection() = default;
};
int main()
{
abstract_connection foo;
}
You defined the copy constructor as yourself (=delete). So Compiler saw that and it doesn't generate the default constructor. So in this case, when define new class abstract_connection that inherited from the base class connection, compiler doesn't know how to do constructor for new derived class abstract_connection. So It reported that error.
Take a look a the following code example which uses class uncopiable similar to boost::noncopyable:
#include <vector>
class uncopiable {
using self = uncopiable;
protected:
uncopiable() {}
~uncopiable() {}
uncopiable(const self&) = delete;
self& operator=(const self&) = delete;
};
struct A {
struct B : uncopiable {
using self = B;
B() {
}
B(B&&) = default;
self& operator=(B&&) = default;
~B() {
}
};
A() { v.emplace_back(); }
~A() {}
private:
std::vector<B> v;
};
int main () {}
Since I wanted to make inner class move only I explicitly specified its move constructor and assignment operator to be default ones but also since I've heard that it's a good practice to specify all of the "special member functions" in such case I inherited it from uncopiable. The problem is that compilation fails with every compiler and something similar to the following error message is displayed (this message is excerpt from the clang one):
/usr/include/c++/v1/memory:1645:31: error: call to implicitly-deleted copy constructor of 'A::B'
...
main.cpp:26:10: note: in instantiation of function template specialization 'std::__1::vector >::emplace_back<>' requested here
main.cpp:19:3: note: copy constructor is implicitly deleted because 'B' has a user-declared move constructor
It could be fixed by removing inheritance (copy operations would still not be created). But writing copy operations to be explicitly deleted inside class after that is also okay.
My questions are: why does it happen? Could it be considered a deficiency of disabling constructors/assignment operators through inheritance of helper classes?
The problem is that your uncopiable class is not moveable. Therefore the default move constructor / assignment operator of the derived class try to use the deleted copy versions.
static_assert(std::is_move_constructible<uncopiable>::value, ""); // fails
static_assert(std::is_move_assignable<uncopiable>::value, ""); // fails
The reason for this is § 12.8 ¶ 9:
If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
X does not have a user-declared copy constructor,
X does not have a user-declared copy assignment operator,
X does not have a user-declared move assignment operator, and
X does not have a user-declared destructor.
Declaring a copy operator or assignment operator as deleted still counts as declaring it.
The solution is of course to declare the move operations for uncopiable.
uncopiable(uncopiable&&) noexcept = default;
uncopiable& operator=(uncopiable&&) noexcept = default;
Note that the move operations should usually be declared noexcept. Especially if you want to use the type in a std::vector like in your example.
This compiles ok on MinGw:
#include <vector>
class uncopiable {
using self = uncopiable;
protected:
uncopiable() {}
~uncopiable() {}
uncopiable(const self&) = delete;
self& operator=(const self&) = delete;
};
struct A {
struct B : uncopiable {
using self = B;
B() {
}
B(B&&) {};
self& operator=(B&&) = default;
~B() {
}
};
A() { v.emplace_back(); }
~A() {}
private:
std::vector<B> v;
};
int main () {
A* a = new A();
}
I have a problem dealing with deprecated since C++11 default generation of copy constructor and copy assignment operator when there is a user-defined destructor.
For most sufficiently simple classes default-generated constructors, operators and destructor are fine. Consider the following reasons to declare destructor:
Making trivial destructor virtual in base class:
// header
class Base1 { public: virtual ~Base1() = default; };
class Base2 { public: virtual ~Base2(); };
// source
Base2::~Base2() = default;
Would all 4 copy and move special methods be generated by compiler in these cases? If yes, then I think it is fine and there is no need to complicate Base1 or Base2.
Printing debug message in destructor:
// header
class D { public: ~D(); };
// source
D::~D() {
#ifdef DEBUG_THIS
std::cout << "D was destructed." << std::endl;
#endif
}
I believe that in this case copy constructor and assignment operator would be generated; but move constructor and assignment operator would not. I want to avoid using deprecated default-generating and disable copying of D. I also want to avoid flooding D with 4 deleted declarations. Is disabling only one copy constructor enough? Is it a good style?
With C++11, a clean way is to follow the pattern used in boost (see here)
You basically create a base class where copy constructor and copy assignment are deleted, and inherit it:
class non_copyable
{
protected:
non_copyable() = default;
~non_copyable() = default;
non_copyable(non_copyable const &) = delete;
void operator=(non_copyable const &x) = delete;
};
class MyClass: public non_copyable
{
...
}
Deleting the copy-constructor and copy-assignment operator is the simplest and clearest way to disable copying:
class X
{
X(X const &) = delete;
void operator=(X const &x) = delete;
};
I don't follow what you are talking about with virtual destructors in the question body . It sounds like you're asking for a way to make your code take up fewer characters of source code, but also be more cryptic to anybody looking at it.
If the list of deleted functions bothers you, you could hide them behind a macro, I guess.
#define NON_COPYABLE_NOR_MOVABLE(T) \
T(T const &) = delete; \
void operator=(T const &t) = delete; \
T(T &&) = delete;
Only copy constructor and copy assignment operator will be generated when destructor is explicitly defaulted. And even then their generation is deprecated. So, in order to have virtual destructor and all default methods, one should write the following:
struct Base
{
Base()=default;
virtual ~Base() = default;
Base(const Base&)=default;
Base& operator=(const Base&)=default;
Base(Base&&)=default;
Base& operator=(Base&&)=default;
};
I would definitely use a macro for more than one such Base class.
In case when destructor is defined by user, 2 special methods are still generated. There are the following ways to disable deprecated generating copy constructor and copy assignment operator:
delete move constructor OR move assignment operator (not quite self-explanatory but very short):
Base(Base&&)=delete; // shorter than deleting assignment operator
delete both copy constructor and copy assignment operator:
Base(const Base&)=delete;
Base& operator=(const Base&)=delete;
Note that you have to explicitly declare default constructor if you need it, e.g. Base()=default;.
Macro or inheriting special class can be used as well for this purpose but I personally prefer deleting move constructor to implementing my own macro or base class. When using Qt or boost, I would prefer Q_DISABLE_COPY(Base) and inheriting boost::noncopyable respectively, because they are already implemented, widely known and recognizable.
http://accu.org/index.php/journals/1896 - detailed explanation and rationale for these issues.
You can do it by this(which is used by Caffe: a fast open framework for deep learning):
// Disable the copy and assignment operator for a class.
#define DISABLE_COPY_AND_ASSIGN(classname) \
private:\
classname(const classname&);\
classname& operator=(const classname&)
Usage example:
class CNoCopyable{
public:
CNoCopyable(int i):m_d(i){}
private:
int m_d;
// add this line(pass class name)
DISABLE_COPY_AND_ASSIGN(CNoCopyable);
};