Error: copy assignment operator not allowed in union - c++

I am compiling the code below when the following erro comes up. I am unable to find the reason.
typedef union {
struct {
const int j;
} tag;
} X;
int main(){
return 0;
}
error: member `<`anonymous union>::`<`anonymous struct> `<`anonymous union>::tag with copy assignment operator not allowed in union
This code compiles fines with gcc though. Gives error only with g++.

In order to have a member of a union of some class type T, T's special member functions (the default constructor, copy constructor, copy assignment operator, and destructor) must be trivial. That is, they must be the ones implicitly declared and defined by the compiler.
Your unnamed struct does not have a trivial copy assignment operator (in fact, it doesn't have one at all) because it has a member variable that is const-qualified, which suppresses generation of the implicitly declared copy assignment operator.

The compiler tries to generate an assignment operator for the union itself, and fails because the active field of the union if not known, so it falls back to a bit-for-bit copy of the object. However, it can't do that either, since struct { const int j; } has a non-trivial assignment operator.
See http://gcc.gnu.org/ml/gcc-help/2008-03/msg00051.html.

Related

Why can't I return an object without move construction in a function? [duplicate]

I'm trying to use this code to demonstrate the use of the copy-constructor. My presumption was that when I have a function that returns by value, my compiler will, by default, perform a move of the object. But when the move-constructor is unavailable, the compiler will copy instead (in C++03, the compiler would copy when returning by-value). So why in the following example does the compiler try to call the explicitly-deleted move-constructor instead of the available copy-constructor? I'm compiling this in GCC 4.7.2.
struct S
{
S() = default;
S(S const &) = default;
S(S&&) = delete;
};
S f() { return S{}; }
int main()
{
f();
}
prog.cpp: In function ‘S f()’:
prog.cpp:8:18: error: use of deleted function ‘S::S(S&&)’
prog.cpp:5:5: error: declared here
Deleted move members are evil. They are not outlawed, because some day, someone will find a clever use for them. But I haven't seen a good use yet.
Deleting a special member is not the same thing as not having a special member. Nowhere is this more obvious than with the move constructor and move assignment operator.
When present, whether deleted, defaulted, or user-defined, the move constructor and the move assignment operator participate in overload resolution. That means that they "compete" with the special copy members. The copy members will typically favor const lvalues, whereas the move members attract rvalues.
When returning a local type from a function (when the local type is the same un-cv-qualified type as the return type), the return statement first considers the return expression as an rvalue, and only if it can't find a suitable constructor, will it then be considered as an lvalue. I.e. matching the proper constructor for returning a local object from a function is a 2-phase operation.
When you don't have a move constructor at all (not even deleted), but you do have a normal copy constructor (takes a const &), then the rvalue from the return statement will match the copy constructor.
When you do have a move constructor, even it is marked deleted, the rvalue from the return statement will find the move constructor a better match than the copy constructor.
Summary
Unless you really know what you are doing, never delete the move members. If you don't want your type to be movable, just do not define the move members and make sure that you do declare copy members, even if the copy members are =default'd.
Update
I suppose it's hard to provide quotes from the Standard on what delete
doesn't do? – DyP
8.4.3 Deleted definitions [dcl.fct.def.delete]
2 A program that refers to a deleted function implicitly or
explicitly, other than to declare it, is ill-formed. [ Note: This
includes calling the function implicitly or explicitly and forming a
pointer or pointer-to-member to the function. It applies even for
references in expressions that are not potentially-evaluated. If a
function is overloaded, it is referenced only if the function is
selected by overload resolution. — end note ]
Update 2
12.8 Copying and moving class objects [class.copy]
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.
[Note: When the move constructor is not implicitly declared or
explicitly supplied, expressions that otherwise would have invoked the
move constructor may instead invoke a copy constructor. — end note ]

Why delete of templete copy constructor cause assignment operator disfunctional?

I have code like below which looks a little bit Confusing. I define a template class. It has a user-defined constructor. When I declare two objects of this template class by "operator =", its user-defined contructor is called to my surprise. Besides, After deleting its copy constructor, the compiling cannot even pass during resolution of "operator =". Does templete constructors have different rules than non-templete class?
#include "iostream"
using namespace std;
template <typename T>
class MyPtr
{
private:
T p_;
public:
MyPtr(T P = NULL): p_(P)
{
cout<<"track!!"<<endl;
}
//MyPtr(const MyPtr<T> & P) = delete;
~MyPtr()
{
}
};
int main()
{
int i=3;
int j=4;
MyPtr<int> p = i;
MyPtr<int> pp = j;
}
Does templete constructors have different rules than non-templete class?
No.
MyPtr<int> p = i; (and MyPtr<int> pp = j;) is copy initialization. Note that this is initialization but not assignment, as the effect p is initialized by the constructor MyPtr::MyPtr(T). e.g.
MyPtr<int> p = i; // initialization; constructors get called
p = j; // assignment; assignment operators (operator=) get called
Before C++17, i would be converted to MyPtr<int> via MyPtr::MyPtr(T) firstly, then the conversion result, i.e. the temporary MyPtr<int> is copied/moved to initialize p; even the copy/move operation is allowd to be optimized, the copy/move constructor is required to be accessible. Declaring copy constructor as delete makes copy constructor unusable and move constructor won't be generated, thus makes MyPtr<int> p = i; ill-formed until C++17.
Since C++17 the optimization is mandatory and the copy/move constructor is not required to be accessible again, that means your code would compile fine with C++17 mode even declaring copy constructor as delete.
If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution. The result of the conversion, which is a prvalue temporary (until C++17) prvalue expression (since C++17) if a converting constructor was used, is then used to direct-initialize the object. The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used. (until C++17)

VS2017: Copy Constructor doesn't work when move constructor is deleted [duplicate]

I'm trying to use this code to demonstrate the use of the copy-constructor. My presumption was that when I have a function that returns by value, my compiler will, by default, perform a move of the object. But when the move-constructor is unavailable, the compiler will copy instead (in C++03, the compiler would copy when returning by-value). So why in the following example does the compiler try to call the explicitly-deleted move-constructor instead of the available copy-constructor? I'm compiling this in GCC 4.7.2.
struct S
{
S() = default;
S(S const &) = default;
S(S&&) = delete;
};
S f() { return S{}; }
int main()
{
f();
}
prog.cpp: In function ‘S f()’:
prog.cpp:8:18: error: use of deleted function ‘S::S(S&&)’
prog.cpp:5:5: error: declared here
Deleted move members are evil. They are not outlawed, because some day, someone will find a clever use for them. But I haven't seen a good use yet.
Deleting a special member is not the same thing as not having a special member. Nowhere is this more obvious than with the move constructor and move assignment operator.
When present, whether deleted, defaulted, or user-defined, the move constructor and the move assignment operator participate in overload resolution. That means that they "compete" with the special copy members. The copy members will typically favor const lvalues, whereas the move members attract rvalues.
When returning a local type from a function (when the local type is the same un-cv-qualified type as the return type), the return statement first considers the return expression as an rvalue, and only if it can't find a suitable constructor, will it then be considered as an lvalue. I.e. matching the proper constructor for returning a local object from a function is a 2-phase operation.
When you don't have a move constructor at all (not even deleted), but you do have a normal copy constructor (takes a const &), then the rvalue from the return statement will match the copy constructor.
When you do have a move constructor, even it is marked deleted, the rvalue from the return statement will find the move constructor a better match than the copy constructor.
Summary
Unless you really know what you are doing, never delete the move members. If you don't want your type to be movable, just do not define the move members and make sure that you do declare copy members, even if the copy members are =default'd.
Update
I suppose it's hard to provide quotes from the Standard on what delete
doesn't do? – DyP
8.4.3 Deleted definitions [dcl.fct.def.delete]
2 A program that refers to a deleted function implicitly or
explicitly, other than to declare it, is ill-formed. [ Note: This
includes calling the function implicitly or explicitly and forming a
pointer or pointer-to-member to the function. It applies even for
references in expressions that are not potentially-evaluated. If a
function is overloaded, it is referenced only if the function is
selected by overload resolution. — end note ]
Update 2
12.8 Copying and moving class objects [class.copy]
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.
[Note: When the move constructor is not implicitly declared or
explicitly supplied, expressions that otherwise would have invoked the
move constructor may instead invoke a copy constructor. — end note ]

Why is the compiler insisting to use move constructor here? [duplicate]

I'm trying to use this code to demonstrate the use of the copy-constructor. My presumption was that when I have a function that returns by value, my compiler will, by default, perform a move of the object. But when the move-constructor is unavailable, the compiler will copy instead (in C++03, the compiler would copy when returning by-value). So why in the following example does the compiler try to call the explicitly-deleted move-constructor instead of the available copy-constructor? I'm compiling this in GCC 4.7.2.
struct S
{
S() = default;
S(S const &) = default;
S(S&&) = delete;
};
S f() { return S{}; }
int main()
{
f();
}
prog.cpp: In function ‘S f()’:
prog.cpp:8:18: error: use of deleted function ‘S::S(S&&)’
prog.cpp:5:5: error: declared here
Deleted move members are evil. They are not outlawed, because some day, someone will find a clever use for them. But I haven't seen a good use yet.
Deleting a special member is not the same thing as not having a special member. Nowhere is this more obvious than with the move constructor and move assignment operator.
When present, whether deleted, defaulted, or user-defined, the move constructor and the move assignment operator participate in overload resolution. That means that they "compete" with the special copy members. The copy members will typically favor const lvalues, whereas the move members attract rvalues.
When returning a local type from a function (when the local type is the same un-cv-qualified type as the return type), the return statement first considers the return expression as an rvalue, and only if it can't find a suitable constructor, will it then be considered as an lvalue. I.e. matching the proper constructor for returning a local object from a function is a 2-phase operation.
When you don't have a move constructor at all (not even deleted), but you do have a normal copy constructor (takes a const &), then the rvalue from the return statement will match the copy constructor.
When you do have a move constructor, even it is marked deleted, the rvalue from the return statement will find the move constructor a better match than the copy constructor.
Summary
Unless you really know what you are doing, never delete the move members. If you don't want your type to be movable, just do not define the move members and make sure that you do declare copy members, even if the copy members are =default'd.
Update
I suppose it's hard to provide quotes from the Standard on what delete
doesn't do? – DyP
8.4.3 Deleted definitions [dcl.fct.def.delete]
2 A program that refers to a deleted function implicitly or
explicitly, other than to declare it, is ill-formed. [ Note: This
includes calling the function implicitly or explicitly and forming a
pointer or pointer-to-member to the function. It applies even for
references in expressions that are not potentially-evaluated. If a
function is overloaded, it is referenced only if the function is
selected by overload resolution. — end note ]
Update 2
12.8 Copying and moving class objects [class.copy]
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.
[Note: When the move constructor is not implicitly declared or
explicitly supplied, expressions that otherwise would have invoked the
move constructor may instead invoke a copy constructor. — end note ]

why the move constructor/move assignment are not implicitly declared and defined as deleted if we only define copy constructor/oper=?

As per the C++ standard 12.8.7:
If the class definition declares a move constructor or move
assignment operator, the implicitly declared copy constructor is
defined as deleted;
and 12.8.18
If the class definition declares a move constructor or move assignment
operator, the implicitly declared copy assignment operator is defined
as deleted;
I am wondering why the move constructor/move assignment are not implicitly declared and defined as deleted (c++11 standard will not generate implicitly declared move constructor/move assignment in this case), if we only defined copy constructor or copy assignment operator?
If this was the case, then using an rvalue as the source of construction or assginment would result in a compilation error instead of falling back to a copy.
A function which does not exist (obviously) does not participate in overload resolution. A function which is defined as deleted does participate in overload resolution normally; if it's chosen, the compilation results in an error.
This code compiles:
struct Normal
{
Normal() {}
Normal(const Normal &) {}
};
int main()
{
Normal n(Normal{});
}
While this code results in an error:
struct Deleted
{
Deleted() {}
Deleted(const Deleted &) {}
Deleted(Deleted&&) = delete;
};
int main()
{
Deleted d(Deleted{});
}
If the move constructor were deleted in that case, then trying to copy-initialise from an rvalue would be an error - the deleted move constructor would be a better match than the copy constructor.
Usually, you'd want copy-initialisation to copy, rather than be disallowed, if you haven't defined move semantics. To give that behaviour, the move constructor is simply not declared at all, so that copy-initialisation uses the copy constructor whether copying from an lvalue or an rvalue. (As long as the copy constructor takes its argument by const reference.)
You can still delete the move operations yourself, if for some reason you want the rather odd quality of only being copyable from an lvalue.