I would like to disable the move constructor in the class. Instead of moving, I would like to base on copy constructor. When I try to write this code:
class Boo
{
public:
Boo(){}
Boo(const Boo& boo) {};
Boo(Boo&& boo) = delete;
};
Boo TakeBoo()
{
Boo b;
return b;
}
during compilation I received error:
error C2280: 'Boo::Boo(Boo &&)': attempting to reference a deleted function
How can I disable the move constructor and force copies instead?
Do not create any move constructor:
class Boo
{
public:
Boo(){}
Boo(const Boo& boo) {};
};
The move constructor is not automatically generated as long as a user-defined copy constructor is present so the copy constructor is called.
Marking a function as =delete makes the function available for overload resolution, but if chosen, the compilation fails; this functionality is not limited to constructors and other special functions (see here). Previously (circa C++03) making the member private achieved a similar result.
Hence, the code as in the sample, effectively means you prohibiting the construction of an object of the class from a temporary or expiring value (rvalues) - the move constructor.
To correct this, remove the move constructor completely. In the case of the class, once a copy constructor is present (user defined), the move is implicitly not generated anyway (move constructor and move assignment operator).
class Boo
{
public:
Boo(){}
Boo(const Boo& boo) {};
//Boo(Boo&& boo) = delete;
};
Related
I'm having compiler errors when trying to emplace_back in a vector of non-copyable but movable objects with a subtle inheritance twist, that should to my knowledge not change the problem.
Is this legal C++ and this a Visual Studio 2015 bug, or am I making an obvious mistake ?
#include <vector>
class Base
{
public:
Base() {}
Base(Base&) = delete;
Base& operator= (Base&) = delete;
};
class Test : public Base
{
public:
Test(int i) : m_i(i) {}
Test(Test&&) = default;
Test& operator= (Test&&) = default;
protected:
int m_i;
};
int main(int argc, char *argv[])
{
std::vector<Test> vec;
vec.emplace_back(1);
}
Output :
error C2280: 'Test::Test(Test &)': attempting to reference a deleted function
Without the inheritance, that is with deleted copy constructor in Test and no base class, it compiles correctly.
Somehow, removing the default in the move-constructor make it compile correctly also, but then I have to define the move constructor and I don't want to go there.
Which means this compiles fine :
#include <vector>
class Test
{
public:
Test(int i) : m_i(i) {}
Test(Test&) = delete;
Test& operator= (Test&) = delete;
Test(Test&&) = default;
Test& operator= (Test&&) = default;
protected:
int m_i;
};
int main(int argc, char *argv[])
{
std::vector<Test> vec;
vec.emplace_back(1);
}
Puzzling ?
The compiler is correct in all the cases you described.
When Test is derived from Base, its defaulted move constructor is defined as deleted because it tries to move Base, which cannot be move-constructed. Test is actually not move-constructible in your first example.
In your second example, with no base class, there's nothing to prevent the defaulted move constructor from being defined, so Test becomes move-constructible.
When you provide a definition for the move constructor, it's up to you to handle Base. If you just write
Test(Test&&) { }
this will just default-construct a Base object, so the move constructor will compile, but it probably won't do what you want.
Base is not move-constructible because it has a user-declared copy constructor, which prevents the implicit declaration of a move constructor - it has no move constructor at all - and its copy constructor is deleted (it couldn't handle rvalues anyway because it takes a non-const reference).
If you make Base move-constructible, by adding, for example,
Base(Base&&) = default;
then Test also becomes move-constructible, and your example will compile.
One last piece of the puzzle: since we have declared a move constructor for Test, why does the error message reference the deleted copy constructor, even in the first case?
For an explanation of std::vector's logic for choosing which constructor to use to copy / move elements during reallocation, see this answer. Looking at the logic that std::move_if_noexcept uses to choose which kind of reference to return, it will be an rvalue reference in our case (when T is not copy-constructible, the condition is always false). So, we'd still expect the compiler to attempt to call the move constructor.
However, one more rule comes into play: a defaulted move constructor that is defined as deleted does not participate in overload resolution.
This is done so that construction from an rvalue can fall back to a copy constructor taking a const lvalue reference, if available. Note that the rule does not apply when the move constructor is explicitly declared as deleted.
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 ]
I have a class like this:
class A{
private:
init(const std::string& s=""){/*do something*/}
public:
A(){init();}
A(const A&){init();}
A(const std::string& s){init(s);}
};
Does it cover all the forms that constructors may be called?
What I am trying to do is, any object creation must call the init() function at first i.e I need to define all the constructors that may be called implicitly or explicitly.
A(const A&)
once you have defined A(A const&) the compiler will not synthesize any other constructors. The only callable constructors will be the ones you declare.
The same is true of A(A&&), as an aside.
It sounds like you have a slight misunderstanding of C++ constructors.
Under specific circumstances classes have certain constructors implicitly declared with defaulted definitions. To avoid constructors that don't call your init() function does not require you to declare these constructors. You can instead follow certain rules that prevent them from being implicitly declared, or you can define some in-class initialization which ensures that the default definitions do the extra initialization you want.
The default constructor is only implicitly declared as defaulted if there are no user-declared constructors.
A copy constructor is only implicitly declared as defaulted if there are no user-declared move constructors or move-assignment operators (and of course no user-declared copy constructor).
A move constructor is only implicitly declared if there are no user-declared copy constructors, copy assignment operators, move constructors, move assignment operators, or destructors (and if the default definition for a move constructor would be valid).
So you could ensure that object construction always calls your init() function by declaring some subset of members that suppresses implicit declarations of any other constructors.
(This slideshow has a handy reference on the conditions for implicit declarations of the special member functions.)
Following the above rules: Declaring this copy constructor, for example, suppresses the default constructor, the move constructor, and the implicitly declared copy constructor. This therefore ensures that no objects of this class can be constructed without calling the init() member function.
struct S {
S(S const &) { init(); }
void init() {}
};
You can also simply use C++11 in-class initialization, which executes even in default definitions, to ensure init() is called for all construction.
struct S {
int x = init();
int init() { return 10; }
// ... whatever constructors you want to define
};
So long as your user-declared constructors don't explicitly initialize x, then all the constructors, both user-declared and implicitly declared, will call init().
I have a hack that does this, but it isn't the most clear on intent.
class A{
private:
bool init(...){...; return true; }
bool initialized = init(...);
public:
// your constructors.
};
Do keep in mind that the parameters to init have not to be dependent on the parameters of the constructor.
For this case, it might be worth considering using implementation inheritance:
class base {
protected:
base(std::string const &s="") { /* equivalent of your `init` */ }
// Or possibly use overloading:
// base() { /* whatever */ }
// base(std::string const &) { /* whatever */ }
};
class A : public base {
A(const std::string& s) : base(s) {}
A(const A&, const std::string& s) : base(s) {}
};
Since A is derived from base, every ctor for A must invoke base's constructor. If you don't use the member initializer list to pass a parameter, it'll be invoked automatically with the default parameter--but creating an A without invoking the base ctor is essentially impossible.
I think you'd better define the move constructor A(A&&), I'm not sure about the policies on automatically generate constructor of different compilers, though C++11 has the explicit definition.
see more info here
Suppose I have a class where the copy constructor is private and not implemented (to make the object non-copyable)
class NonCopyable {
// whatever
private:
NonCopyable( const NonCopyable&);
void operator=(const NonCopyable&);
};
Now in some member function of the same class I write code that returns an object of that class:
NonCopyable NonCopyable::Something()
{
return NonCopyable();
}
which is a case when RVO could kick in.
RVO still requires that a copy constructor is accessible. Since the possible call to the copy constructor is done from within the same class member function the copy constructor is accessible. So technically RVO is possible despite the fact that the intent was to prohibit using the copy constructor.
Is RVO allowed in such cases?
Yes, RVO would be allowed in this case - at least if the caller of Something() was a class member or friend.
I think this is one reason why private inheritance of a non-copyable class is better than doing it 'manually' in each class you want to prevent copying in. In that case there's no accidental loophole.
For example, using boost::noncopyable:
class NonCopyable : private boost::noncopyable {
public:
NonCopyable() {};
NonCopyable Something();
};
NonCopyable NonCopyable::Something()
{
return NonCopyable(); // causes compile time error, not link time error
}
Your example is quite interesting.
This is the typical C++03 declaration.
class NC {
public:
NC NC::Something() {
return NC();
}
private:
NC(NC const&);
NC& operator=(NC const&);
};
Here, as noted, RVO may kick in even though we semantically wanted to avoid copying.
In C++03, the solution is to delegate:
class NC: boost::noncopyable {
public:
NC NC::Something() { // Error: no copy constructor
return NC();
}
};
In C++11, we have the alternative of using the delete keyword:
class NC {
public:
NC NC::Something() { // Error: deleted copy constructor
return NC();
}
private:
NC(NC const&) = delete;
NC& operator=(NC const&) = delete;
};
But sometimes, we want to prevent copy, but would like to allow Builder (as in the Pattern).
In this case, your example works as long as RVO kicks in, which is a bit annoying as it is, in essence, non-standard. A definition of the copy constructor should be provided but you wish it not to be used.
In C++11, this usecase is supported by deleting copy operations and defining move operations (even privately).
It is allowed, but you may get a link error because the copy constructor is not implemented.
If you provide a body for NonCopyable( const NonCopyable&), it would work.
One important point may overshadow the actual question.
What is the use case of such function if RVO is allowed ?
This function can be called in 3 ways and 2 of them will be a compiler error:
NonCopyable obj;
NonCopyable obj2 = obj; // 1 --> error
NonCopyable &r = obj; // 2 --> error
const NonCopyable &rc = obj; // 3 --> ok, but dangerous (may lead to UB)
One can't use the returned object effectively, so it really doesn't matter if the RVO is allowed or not.
This question already has answers here:
Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?
(3 answers)
Closed 5 years ago.
This is just a quick question to understand correctly what happens when you create a class with a constructor like this:
class A
{
public:
A() {}
};
I know that no default constructor is generated since it is already defined but are copy and assignment constructors generated by the compiler or in other words do i need to
declare a private copy constructor and a private assignment operator in order to prevent this from happening?
class A
{
private:
// needed to prevent automatic generation?
A( const A& );
A& operator=( const A& );
public:
A() {}
};
Yes, copy constructor and copy assignment operators are still created even if you declare your own default constructor.
The creation of those are only suppressed if you declare your own copy constructor or copy assignment operator in the class definition respectively.
Note that it is possible to have both your own copy constructor, and a compiler provided one:
struct A {
A() { }
A(A const&, int foo);
}; // compiler declares a copy constructor now
// make the second parameter have a default argument
// now this constructor is a copy constructor too.
inline A::A(A const&, int foo = 0) {
}
int main() {
A a;
A b = a; // ambiguity between compiler's one and our custom one!
}
The Standard however allows compilers to accept this code - but the effect is similar to having undefined behavior: The program is ill-formed, but no warning/error is required for that program. (early GCC versions don't reject this code, recent ones reject it).
Yes. The copy constructor, assignment operator, and destructor are always created regardless of other constructors and operators.
If you want to disable one, what you've got there is perfect. It's quite common too.
If you want to disable copying and assigning, then it might be better to inherit from a class that has a private copy constructor and assignment operator (boost::noncopyable is a ready-made one).
1) Less repetitive typing.
2) Self-documenting (hopefully).
3) Stronger checks that those operations can't be invoked (the class itself, nor the friends can make copies either - that would result in a compiler, not a linker error).
4) Won't hide the default constructor :)
#include <boost/noncopyable.hpp>
class X : boost::noncopyable
{
};
int main()
{
X a, b; //has default constructor
//X c(a); //but can't be copied
//a = b; //or assigned
}