Reputation: 3087
I want to make some classes use automatically generated constructors, but be non-copyable (but still movable). Currently I'm doing it like this:
class A
{
public:
A() = default;
A(const A&) = delete;
A(A&&) = default;
A& operator=(const A&) = delete;
A& operator=(A&&) = default;
}
I wonder if it's really necessary to be so explicit. What if I wrote it like this:
class A
{
A(const A&) = delete;
A& operator=(const A&) = delete;
}
Would it still work the same? What is the minimal set of defaults and deletes for other cases - non-copyable non-movable class, and class with virtual destructor?
Is there any test code I can use to quickly see which constructors are implicitly created?
Upvotes: 5
Views: 1221
Reputation: 15334
I would suggest you should rarely need to do this. And in the few circumstances where you do need to do it, explicitly declaring which special functions are deleted and which are defaulted may be no bad thing.
The normal reason why you might need to explicitly define or delete special member functions is if your class is some sort of resource managing class. For example it has owning pointers and there is no way of the compiler knowing what the ownership of that resource is. However, as is described in the Rule of Zero article:
C++ allows us to encapsulate ownership policies into generic reusable classes. This is the important bit! Most often, our ownership needs can be catered for by "ownership-in-a-package" classes.
Common "ownership-in-a-package" classes are included in the standard library: std::unique_ptr and std::shared_ptr. Through the use of custom deleter objects, both have been made flexible enough to manage virtually any kind of resource.
So it is very rare for us to need to write out own resource managing class anymore. It should normally be possible to build up a class from from other classes that already have the ownership baked in. And then the default special member functions should be as you expect.
For example, if you have a std::unique_ptr
member then your class is implicitly uncopyable or if you have a const
member then your class is implicitly unassignable.
That said, if you do need to explicitly make a class uncopyable, @n.m. succinctly outlined the rules on when constructors/assignment operators are implicitly defined and so you need at least:
A() = default;
A(A&&) = default;
A& operator=(A&&) = default;
And I agree with you that C++11 is expressive enough that we don't need boost for this any more.
Upvotes: 1
Reputation: 1250
You can avoid definition of deleted copy c'tor and assignment operator, using boost noncopyable
this way the intent may be even more explicit and clear, than using the "delete" keyword
you can simply use it like:
#include <boost/utility.hpp>
class A : boost::noncopyable {
public:
A () = default;
A (A&&) = default;
A& operator= (A&&) = default;
};
Upvotes: 0
Reputation: 218770
Is there any test code I can use to quickly see which constructors are implicitly created?
Yes. For example:
#include <type_traits>
class A
{
public:
A() = default;
A(A&&) = default;
A& operator=(A&&) = default;
};
static_assert(std::is_nothrow_default_constructible<A>::value,
"A must be noexcept default constructible");
static_assert(std::is_nothrow_destructible<A>::value,
"A must be noexcept destructible");
static_assert(!std::is_copy_constructible<A>::value,
"A must not be copy constructible");
static_assert(!std::is_copy_assignable<A>::value,
"A must not be copy assignable");
static_assert(std::is_nothrow_move_constructible<A>::value,
"A must be noexcept move constructible");
static_assert(std::is_nothrow_move_assignable<A>::value,
"A must be noexcept move assignable");
Above I've used _nothrow_
in some of the traits. Remove that part if you want to allow the associated special member to throw an exception.
Upvotes: 2
Reputation: 119877
This will not work because no default constructor will be automatically created for you. No default constructor will be created because you have declared a copy constructor. It is defined as deleted, but it is user-declared nonetheless, so there is no implicitly defaulted default constructor.
The condensed rules for implicitly created constructors are:
Upvotes: 6