I have this simple program that doesn't compile
#include <future>
class Foo
{
public:
~Foo();
std::future<int> f;
};
Foo getFoo()
{
return Foo();
}
int main()
{
Foo b = getFoo();
}
which, I guess, makes sense. Foo is not copyable because future is not copyable.
In function 'Foo getFoo()':
13:16: error: use of deleted function 'Foo::Foo(const Foo&)'
4:7: note: 'Foo::Foo(const Foo&)' is implicitly deleted because the default definition would be ill-formed:
4:7: error: use of deleted function 'std::future<_Res>::future(const std::future<_Res>&) [with _Res = int]'
In file included from 2:0:
/usr/include/c++/4.9/future:686:7: note: declared here
future(const future&) = delete;
^
In function 'int main()':
18:20: error: use of deleted function 'Foo::Foo(const Foo&)'
What I don't understand is why it compiles when I remove the destructor:
#include <future>
class Foo
{
public:
//~Foo();
std::future<int> f;
};
Foo getFoo()
{
return Foo();
}
int main()
{
Foo b = getFoo();
}
Isn't this destructor generated by default anyway? What effect does it have on the class being copyable/movable?
The implicitly generated copy constructor is defined as deleted because your class contains a std::future, which is not copyable. This means your class is not copyable in either case.
It may however be movable. Usually the example you show could also use a move constructor, but the implicit move constructor is not declared when you declare a destructor manually, making Foo in the first example also not movable, while it is in the second one.
As mentioned by #Ayxan in a comment under the question, since C++17 both your examples would compile, because although Foo isn't movable in the first example, since C++17 mandatory copy elision rules apply and there would only be one Foo constructed directly into Foo b in your example. No temporary Foo objects would exist and the class would not need to be copyable or movable for this.
In general you should always implement copy/move constructor and assignment operators manually if you have a custom destructor. That is known as the rule of 3/5. The language does not currently enforce this rule for the copy operations, although the implicit declaration of the copy operations if a user-declared destructor exists has been deprecated since C++11. The language does however enforce the rule for the move operations by not implicitly declaring the move operations if a user-declared destructor is present.
A custom destructor is not often needed, so you should probably not declare it in the first place. If you need to declare it, because e.g. you need it to be virtual (in which case it should just be defaulted with virtual ~Foo() = default), then you can default the move operations:
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;
But if your destructor has a custom definition that does have statements in it that actually perform some work, you likely must implement these methods yourself with proper semantics, so that you don't run into problems when the class is moved.
In c++11, The implicit definition of a copy constructor as defaulted
is deprecated if the class has a user-declared copy assignment
operator or a user-declared destructor.
It's the standard of the language.
Note that you have a noncopyable member too.
Related
As far as I know, in C++ default constructors are declared (and defined if needed) implicitly if there is no user-defined default constructors. However, a user can declare a default constructor explicitly with the default keyword. In this post the answers are mainly about the difference between the implicit and default terms, but I didn't see an explanation about whether there is some difference between declaring a constructor as default and not declaring it at all.
As an example:
class Entity_default {
int x;
public:
Entity_default() = default;
}
class Entity_implicit {
int x;
}
In the example above, I declare a constructor for Entity_default as default and let the compiler declare a default constructor implicitly for Entity_implicit. I assume I do call these constructors later on. Is there any difference between these constructors in practice?
To the best of my knowledge, there is no functional or theoretical difference, both are still "trivial."
Uses of an explicit default constructors:
To ensure it exists when it would not otherwise be created, i.e. if a different constructor exists
You can default it in a different compilation unit:
Header file:
struct Foo
{
std::string bar;
Foo() noexcept;
~Foo();
};
Source file:
Foo::Foo() noexcept = default;
Foo::~Foo() = default;
Useful if you don't want an inline constructor to save code size or ensure ABI compatibility. Note that at this point, it is no longer a trivial object.
Consider the following example:
#include <iostream>
#include <string>
#include <utility>
template <typename Base> struct Foo : public Base {
using Base::Base;
};
struct Bar {
Bar(const Bar&) { }
Bar(Bar&&) = delete;
};
int main() {
std::cout << std::is_move_constructible<Bar>::value << std::endl; // NO
std::cout << std::is_move_constructible<Foo<Bar>>::value << std::endl; // YES. Why?!
}
Why does the compiler generate a move constructor despite the base class being non-move-constructible?
Is that in the standard or is it a compiler bug? Is it possible to "perfectly propagate" move construction from base to derived class?
Because:
A defaulted move constructor that is defined as deleted is ignored by overload resolution.
([class.copy]/11)
Bar's move constructor is explicitly deleted, so Bar cannot be moved. But Foo<Bar>'s move constructor is implicitly deleted after being implicitly declared as defaulted, due to the fact that the Bar member cannot be moved. Therefore Foo<Bar> can be moved using its copy constructor.
Edit: I also forgot to mention the important fact that an inheriting constructor declaration such as using Base::Base does not inherit default, copy, or move constructors, so that's why Foo<Bar> doesn't have an explicitly deleted move constructor inherited from Bar.
1. The behavior of std::is_move_constructible
This is expected behavior of std::is_move_constructible:
Types without a move constructor, but with a copy constructor that accepts const T& arguments, satisfy std::is_move_constructible.
Which means with a copy constructor it's still possible to construct T from rvalue reference T&&. And Foo<Bar> has an Implicitly-declared copy constructor.
2. The implicitly-declared move constructor of Foo<Bar>
Why does compiler generates move constructor despite base class being non-move-constructible?
In fact, the move constructor of Foo<Bar> is defined as deleted, but note that the deleted implicitly-declared move constructor is ignored by overload resolution.
The implicitly-declared or defaulted move constructor for class T is
defined as deleted in any of the following is true:
...
T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors);
...
The deleted implicitly-declared move constructor is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue).
3. The different behavior between Bar and Foo<Bar>
Note that the move constructor of Bar is declared as deleted explicitly, and the move constructor of Foo<Bar> is implicitly-declared and defined as deleted. The point is that the deleted implicitly-declared move constructor is ignored by overload resolution, which makes it possible to move construct Foo<Bar> with its copy constructor. But the explicitly deleted move constructor will participate in overload resolution, means when trying to move constructor Bar the deleted move constructor will be selected, then the program is ill-formed.
That's why Foo<Bar> is move constructible but Bar is not.
The standard has an explicit statement about this. $12.8/11 Copying and moving class objects
[class.copy]
A defaulted move constructor that is defined as deleted is ignored by overload resolution ([over.match], [over.over]). [ Note: A deleted move constructor would otherwise interfere with initialization from an rvalue which can use the copy constructor instead. — end note ]
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What’s the point in defaulting functions in C++11?
C++11 introduced defaulted methods (e.g. void myMethod() = default;).
What does it do to methods (how do methods behave after being defaulted). How do I use them properly (what are its uses)?
There are a number of class members that are considered "special member functions" by the C++ standard. These are:
The default constructor (a constructor that can be called with no parameters).
The copy constructor (a constructor that can be called with one parameter that is the object type as an lvalue reference).
The copy assignment operator (an operator= overload that can be called with one parameter that is the object type as either an lvalue reference or a value).
The move constructor (a constructor that can be called with one parameter that is the object type as an rvalue reference).
The move assignment operator (an operator= overload that can be called with one parameter that is the object type as either an rvalue reference or a value).
The destructor.
These member functions are special in that the language does special things with them on types. Another thing that makes them special is that the compiler can provide definitions for them if you do not. These are the only functions that you can use the = default; syntax on.
The issue is that the compiler will only provide a definition under certain conditions. That is, there are conditions under which a definition will not be provided.
I won't go over the entire list, but one example is what others have mentioned. If you provide a constructor for a type that is not a special constructor (ie: not one of the constructors mentioned above), a default constructor will not be automatically generated. Therefore, this type:
struct NoDefault
{
NoDefault(float f);
};
NoDefault cannot be default constructed. Therefore, it cannot be used in any context where default construction is needed. You can't do NoDefault() to create a temporary. You can't create arrays of NoDefault (since those are default constructed). You cannot create a std::vector<NoDefault> and call the sizing constructor without providing a value to copy from, or any other operation that requires that the type be DefaultConstructible.
However, you could do this:
struct UserDefault
{
UserDefault() {}
UserDefault(float f);
};
That would fix everything, right?
WRONG!
That is not the same thing as this:
struct StdDefault
{
StdDefault() = default;
StdDefault(float f);
};
Why? Because StdDefault is a trivial type. What does that mean? I won't explain the whole thing, but go here for the details. Making types trivial is often a useful feature to have, when you can do it.
One of the requirements of a trivial type is that it does not have a user-provided default constructor. UserDefault has a provided one, even though it does the exact same thing as the compiler-generated one would. Therefore, UserDefault is not trivial. StdDefault is a trivial type because = default syntax means that the compiler will generate it. So it's not user-provided.
The = default syntax tells the compiler, "generate this function anyway, even if you normally wouldn't." This is important to ensure that a class is a trivial type, since you cannot actually implement special members the way the compiler can. It allows you to force the compiler to generate the function even when it wouldn't.
This is very useful in many circumstances. For example:
class UniqueThing
{
public:
UniqueThing() : m_ptr(new SomeType()) {}
UniqueThing(const UniqueThing &ptr) : m_ptr(new SomeType(*ptr)) {}
UniqueThing &operator =(const UniqueThing &ptr)
{
m_ptr.reset(new SomeType(*ptr)); return *this;
}
private:
std::unique_ptr<SomeType> m_ptr;
};
We must write every one of these functions to make the class copy the contents of the unique_ptr; there's no way to avoid that. But we also want this to be moveable, and the move constructor/assignment operators won't automatically be generated for us. It'd silly to re-implement them (and error-prone if we add more members), so we can use the = default syntax:
class UniqueThing
{
public:
UniqueThing() : m_ptr(new SomeType()) {}
UniqueThing(const UniqueThing &ptr) : m_ptr(new SomeType(*ptr)) {}
UniqueThing(UniqueThing &&ptr) = default;
UniqueThing &operator =(const UniqueThing &ptr)
{
m_ptr.reset(new SomeType(*ptr)); return *this;
}
UniqueThing &operator =(UniqueThing &&ptr) = default;
private:
std::unique_ptr<SomeType> m_ptr;
};
Actually, default can only apply to special methods - i.e. constructors, destructors, assignment operator:
8.4.2 Explicitly-defaulted functions [dcl.fct.def.default]
1 A function definition of the form:
attribute-specifier-seqopt decl-specifier-seqopt declarator = default ;
is called an explicitly-defaulted definition. A function that is explicitly defaulted shall
— be a special member function,
— have the same declared function type (except for possibly differing ref-qualifiers and except that in
the case of a copy constructor or copy assignment operator, the parameter type may be “reference to
non-const T”, where T is the name of the member function’s class) as if it had been implicitly declared,
and
— not have default arguments.
They behave the same as if the compiler generated them and are useful for cases like:
class Foo{
Foo(int) {}
};
here, the default constructor doesn't exist, so Foo f; wouldn't be valid. However, you can tell the compiler that you want a default constructor without the need to implement it yourself:
class Foo{
Foo() = default;
Foo(int) {}
};
EDIT: Pointed out by #Nicol Bolas in the comments, this truly doesn't explain why you'd prefer this over Foo() {}. What I'm guessing is: if you have a class w/ implementations separated in an implementation file, your class definition (if you don't use =default) would look like:
class Foo{
Foo();
Foo(int);
};
What I'm assuming is that the =default is meant to provide an idiomatic way of telling you "we're not doing anything special in the constructor". With the above class definition, the default constructor could very well not value-initialize the class members. With the =default you have that guarantee just by looking at the header.
Using = default on a constructor or copy-constructor means that the compiler will generate that function for you during compile-time. This happens normally when you exclude the respective functions from your class/struct. And in the case where you define your own constructor, this new syntax allows you to explicitly tell the compiler to default-construct the constructor where it normally won't. Take for instance:
struct S {
};
int main() {
S s1; // 1
S s2(s1); // 2
}
The compiler will generate both a copy-constructor and a default-constructor, thus allowing us to instantiate an S object like we did (1) and copy s2 into s1 (2). But if we define our own constructor, we find that we are unable to instantiate in the same way:
struct S {
S(int);
};
int main() {
S s; // illegal
S s(5); // legal
}
This fails because S has been given a custom-defined constructor, and the compiler won't generate the default one. But if we still want the compiler to give us one, we can explicitly convey this using default:
struct S {
S(int);
S() = default;
S(const S &) = default;
};
int main() {
S s; // legal
S s(5); // legal
S s2(s); // legal
}
Note, however, that only certain functions with certain function-signatures can be overloaded. It follows that this will fail because it is neither a copy-constructor nor a default-constructor or a move or assignment operator:
struct S {
S(int) = default; // error
};
We are also able to explicitly define the assignment operator (just like the default/copy-constructor, a default one is generated for us when we do not write out our own). So take for example:
struct S {
int operator=(int) {
// do our own stuff
}
};
int main() {
S s;
s = 4;
}
This compiles, but it won't work for us in the general case where we want to assign another S object into s. This is because since we wrote our own, the compiler doesn't provide one for us. This is where default comes into play:
struct S {
int operator=(int) {
// do our own stuff
}
S & operator=(const S &) = default;
};
int main() {
S s1, s2;
s1 = s2; // legal
}
But technically it's superfluous to define the assignment operator, copy, or move constructor as default when there is no other function "overriding" it as the compiler will provide one for you in that case anyway. The only case in which it won't provide you one is where you define your own one (or variation thereof). But as a matter of preference, asking the compiler to provide a default function using the new aforementioned syntax is more explicit and easier to see and understand if intentionally left out for the compiler.
In §12 of the standard every special member function has a set of rules which cause it to be implicitly declared as defaulted and another set of rules which cause a defaulted [special member function to be] defined as deleted.
This makes it seem (to me) that there are 3 potential states when no user-declared version is present for special member functions: declared and defined (defaulted), declared and undefined (deleted), and undeclared. Is this accurate? If so, what point is there as opposed to cutting out the 'undeclared' option?
* declared as defaulted seems like a mistake, shouldn't it be "defined" as defaulted?
The difference between a deleted constructor and an implicitly undeclared constructor is that the deleted constructor participates in overload resolution, whereas the constructor that doesn't exist, doesn't participate in overload resolution.
Example:
This class is default constructible. The compiler does not implicitly declare a defaulted constructor for it.
struct A
{
template <class ...T>
A(T...) {}
};
int main()
{
A a; // ok
}
If the compiler did declare a default constructor for it, and if that default constructor was defined as deleted, then A would not be default constructible. That can be simulated with:
struct A
{
A() = delete; // pretend the compiler implicitly declared and defined this
template <class ...T>
A(T...) {}
};
int main()
{
A a;
}
error: call to deleted constructor of 'A'
A a;
^
Similar problems appear with the move constructor. If the compiler decides to implicitly declare it and define it as deleted, then one can not construct such a class from an rvalue, even if it has a viable copy constructor:
#include <type_traits>
struct A
{
A();
A(const A&);
A(A&&) = delete; // pretend compiler declared and defined
};
int main()
{
A a = std::declval<A>();
}
error: call to deleted constructor of 'A'
A a = std::declval<A>();
^ ~~~~~~~~~~~~~~~~~
But if the compiler does not implicitly declare a deleted move constructor, then things just work:
#include <type_traits>
struct A
{
A();
A(const A&);
};
int main()
{
A a = std::declval<A>(); // ok
}
Indeed, if the compiler did implicitly declare a deleted move constructor for A, there would be a awful lot of broken C++98/03 code when recompiled in C++11! :-)
I not sure I agree with your summary:
There are basically three states: User Defined, Deleted or Compiler Generated
declared and defined
This means the user has explicitly declared them in the class and provided definitions.
declared and deleted
This means the user has explicitly declared them as deleted (ie they are not available).
undeclared
The user has not provided a declaration (and thus can not provide a definition).
In this case the the compiler will generate a version of the method.
class Foo
{
public:
explicit Foo() {}
explicit Foo(Foo&) {}
};
Foo d = Foo();
error: no matching function for call to 'Foo::Foo(Foo)'
I tried changing Foo(Foo&) to Foo(Foo) as the error suggests, which AFAIK is not a valid constructor, and sure enough I get:
error: invalid constructor; you probably meant ‘Foo (const Foo&)’
What gives? How do I resolve this? (This is on GCC by the way)
There are two questionable things that you have in your copy constructor.
First, you've made the copy-constructor explicit (which is a questionable thing to do), so you would (in theory) need to do:
Foo d( (Foo()) );
Second, your copy constructor takes a reference and not a const reference which means that you can't use it with a temporary Foo.
Personally, I'd just remove explicit from the copy-constructor and make it take a const reference if possible.
Note that the explicit on your default constructor has no effect.[*] explicit only has an effect on constructors that can be called with a single parameter. It prevents them being used for implicit conversions. For constructors that take only zero or only two or more parameters, it has no effect.
[Note: there can be a difference between:
Foo d;
and
Foo d = Foo();
but in this case you have a user-declared default constructor so this doesn't apply.]
Edit:
[*] I've just double checked this and 12.3.1 [class.conv.ctor] says that you can make a default constructor explicit. In this case the constructor will be used to perform default-initialization or value-initialization. To be honest, I don't understand the value of this as if you have a user-declared constructor then it's a non-POD type and even local objects of non-POD type are default-initialized if they don't have an initializer which this clause says can be done by an explicit default constructor. Perhaps someone can point out a corner case where it does make a difference but for now I don't see what effect explicit has on a default constructor.
You don't want to mark either of those constructors as explicit - the compiler needs to use both of them, particularly the copy constructor, implicitly. What are you trying to achieve by marking them explicit?
First, neither the default constructor nor the copy constructor should ever be explicit. You only need to make a constructor explicit if it takes a single argument of some other type, to prevent implicit conversion from that type. The copy constructor takes a reference to the class itself, so there is no danger of an unwanted conversion.
Second, make sure that the copy constructor takes a const reference.
Third, Foo f; is the right way to have a default-constructed object of class foo. Note that Foo f(); is wrong, because the compiler will interpret that as a declaration of function f() which returns an object of class Foo.
Fourth, if you have written your own copy constructor, then you should also write the assignment operator.
class Foo
{
Foo() {} // no need to make explicit. Nothing to convert from.
Foo(const &Foo f) {} // again, nothing wrong with conversion from Foo to Foo
explicit Foo(int a) {} // need explicit to prevent accidental passing of an int
// to a function that takes Foo as an argument
};
Try without the explicit? I think that:
Foo foo = Foo()
creates an implicit copy, thus the explicit copy constructor doesn't get triggered.
Edit:
This is only half the answer. See Charles Bailey or UncleBens post for why const is necessary.
A copy constructor shouldn't be explicit (which makes it uncallable here and in many other perfectly reasonable contexts, such as when passing or returning by value).
Next it should take the argument by const reference, since otherwise it can't bind to temporaries.
Foo f = Foo();
^^^^^
|
--- this is a temporary that cannot be passed to a function
that accepts a non-const reference
Furthermore, there is no reason to make the default constructor explicit: this keyword only makes sense for constructors (other than the copy constructor) that can be called with exactly one argument, in which case it prevents implicit conversions of other types into Foo via that constructor. For example, if a constructor taking an int were explicit, situations like these wouldn't compile:
Foo f;
f = 1; //assuming no operator= overload for (types convertible from) int
//this implicitly performs f = Foo(1);
Foo g = 10;
void x(Foo);
x(20);
All in all:
class Foo
{
public:
Foo();
Foo(const Foo&);
//...
};
Foo x = Foo();
And furthermore, if neither of those constructors is meant to do anything, you needn't define them at all - the compiler will provide them automatically (if you define any other constructors, the default constructor will not be automatically generated, though).
Foo d = Foo();
should be
Foo d;
The first line creates a Foo instance and then copies it to d;
Your problem is in the instantiation. You don't need Foo d = Foo(); for a default constructor.
Keep your class the same, but try this for instantiation:
Foo d;
In fact, you don't even need Foo d = Foo(arguments); for constructing with parameters. That should be like this:
Foo d(arguments);
The compiler is telling you... Use this:
Foo(const Foo&) {}
You can cure the problem in either of two ways. One (already suggested by Randolpho) is to eliminate using the copy ctor. The other is to write a proper copy ctor:
Foo (Foo const &) {}
You generally want to do both.
Edit: Looking at it, my last comment is easy to mis-construe. Quite a few classes do not need a copy ctor at all, but if you do need a copy ctor, it should normally have the form above (not explicit, and taking a const reference as the parameter).
class Foo
{
public:
explicit Foo() {}
explicit Foo(const Foo&) {}
};
Foo d = Foo()