Passing argument of object without copy constructor? - c++

I was looking into move semantics in C++11, and got to the part where something like:
SomeClass bar = createSomeClass(); //creates some object of SomeClass
foo(bar);
foo(createSomeClass());
I know that in the first foo the compiler will call SomeClass's copy constructor and the second foo the compiler will call an overloaded move constructor since createSomeClass() returns an R-value.
What if I don't have a copy constructor declared at all? How does the compiler actually know how to copy these objects then?

A default copy constructor will be automatically provided (performing a memberwise copy) unless the class declares a copy constructor, deletes the copy constructor, or declares a move operation. A default copy constructor will still be automatically provided is a user-declared destructor or copy assignment operator exists, but this is deprecated.
A default copy assignment operator will be automatically provided (performing a memberwise copy) unless the class declares a copy assignment operator, deletes the copy assignment operator, or declares a move operation. A default copy constructor will still be automatically provided is a user-declared destructor or copy constructor exists, but this is deprecated.
A default move constructor and move assignment operator will be automatically provided only if the class does not declare any copy operations, move operations, or a destructor.

Related

Why object could be "moved" even lacks move constructor and move assignment operator?

http://en.cppreference.com/w/cpp/language/rule_of_three
I have begun with c++11 a couple of months ago
and have watched the rule of five.
So.. I started putting copy constructor/copy assignment operator/move constructor/move assignment operator with default keyword on every class having virtual destructor.
because the rule told me that if you declare explicit destructor then your class doesn't have its implicit move constructor and move assignment operator anymore.
So I think gcc is going to complain to me that below class due to lack of move constructor and move assignment operator.
But It works well! What happend??
class Interface {
public:
virtual ~Interface() = default; // implicit destructor
};
class ImplA : public Interface {
public:
virtual ~ImplA() = default; // implicit destructor
};
ImplA first;
ImplA second(first); // copy constructor, OK. understood it.
ImplA third(std::move(first)); // move constructor, it's OK. Why?
second = first; // copy assignment, OK. understood it.
second = std::move(first); // move assignment, it's also OK. Why?
So I think gcc is going to complain to me that below class due to lack of move constructor and move assignment operator.
Because the operations required could be performed via copy constructor and copy assignment operator. Interface still has copy constructor and copy assignment operator which are implcitly declared. And rvalues are always possible to be bound to const Interface&.
More precisely, even without move constructor and move assignment operator provided, Interface is still MoveConstructible,
A class does not have to implement a move constructor to satisfy this
type requirement: a copy constructor that takes a const T& argument
can bind rvalue expressions.
and MoveAssignable.
The type does not have to implement move assignment operator in order
to satisfy this type requirement: a copy assignment operator that
takes its parameter by value or as a const Type&, will bind to rvalue
argument.
BTW: If you make the move constructor and move assignment operator delete explicitly then both copy and move operation would fail. Using with an rvalue expression the explicitly deleted overload will be selected and then fails. Using with an lvalue expression would fail too because copy constructor and copy assignment operator are implicitly declared as deleted because of the declaration of move constructor or move assignment operator.

Understanding Default Move Constructor Definition

While reading about the move constructor from the current standard, I can see the following about this:
12.8 Copying and moving class objects
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 ]
I think note section clearly mentions that fall-back for default move constructor would be copy constructor. To understand this concept I wrote the small program to understand this concept.
#include<iostream>
struct handleclass {
public:
handleclass():length{0}, p{nullptr} {}
handleclass(size_t l):length{l},p{new int[length]} { }
~handleclass() { delete[] p; }
size_t length;
int* p;
};
handleclass function(void) {
handleclass x(10);
return x;
}
int main() {
handleclass y;
std::cout<<y.length<<std::endl;
y = function();
std::cout<<y.length<<std::endl;
handleclass a;
handleclass b(10);
a = std::move(b);
return 0;
}
Obviously this program is incorrect and would have undefined behaviour(terminate) due to the shallow copy of resources by two objects. But my focus is to understand the default move constructor generated and used in program. I hope this example make sense.
In the above program, in both cases where move constructor should be called, it appears to me that compiler is using default copy constructor.
Based on the above rule mentioned in the standard I think we should have got the compiler error as now program explicitly trying to call the move constructor and neither user has implemented nor compiler generates default(implicitly) as above rule does not satisfy?.
However this is getting compiled without any warning/error and running successfully. Could somebody explains about default(implicitly) move constructor concepts? Or I am missing something?.
You're forgetting about copy elision which means that y = function(); may not actually invoke any copy or move constructors; just the constructor for x and the assignment operator.
Some compilers let you disable copy elision, as mentioned on that thread.
I'm not sure what you mean by "in both cases where move constructor should be called". There are actually zero cases where move constructor should be called (your object does not have a move constructor), and one case where copy constructor could be called (the return statement) but may be elided.
You have two cases of assignment operator: y = function(); and a = std::move(b); . Again, since your class does not have a move-assignment operator, these will use the copy-assignment operator.
It would probably help your testing if you added code to your object to cout from within the copy constructor and move constructor.
Indeed, there is no implicit move constructor due to the user-declared destructor.
But there is an implicit copy constructor and copy-assignment operator; for historical reasons, the destructor doesn't inhibit those, although such behaviour is deprecated since (as you point out) it usually gives invalid copy semantics.
They can be used to copy both lvalues and rvalues, and so are used for the function return (which might be elided) and assignments in your test program. If you want to prevent that, then you'll have to delete those functions.
A move constructor and move assignment operator have not been implicitly declared because you have explicitly defined a destructor. A copy constructor and copy assignment operator have been implicitly declared though (although this behaviour is deprecated).
If a move constructor and move assignment operator have not been implicitly (or explicitly) declared it will fall back to using the copy equivalents.
As you are trying to call move-assignment it will fall back to using copy assignment instead.

What happens when I make a assignment to object which has copy constructor but no assignment operator?

What happens when I make a assignment to object which has copy constructor but no assignment operator?
Will it call compiler's assignment operator, performing memberwise copy?
All classes have an assignment operator, unless you explicitly delete it (not possible prior to C++11). If you do not supply your own implementation, the compiler will supply one for you.
That is the main reason behind the rule of three: if you have a copy constructor, it is nearly certain that you will need an assignment operator and a destructor as well.
The copy constructor plays no role in assignment, the default assignment operator will be called that'll do a bit-wise copy of built-in type members and call assignment operator on object members of class type.
Yes you'll be accessing the default assignment operator generator by compiler, if you don't provide one.
But in general if a class defines one of the following it should probably explicitly define all three
destructor
copy constructor
copy assignment operator
I don't know what do you mean by assignment ( in compiler's context ). So, Let me try by an example.Let's say we have a class Test;
Test a,c; //default constructor would be called for both.
Test b = a; //copy constructor would be called for b as we are creating that object.
c = b; //assignment operator would be called for c as we are changing content's of c.
So, if class Test contains plain objects then it wouldn't matter if you define OR not compiler would do bit-wise copying for you. But if your class contains pointers, then you should explicitly define your copy constructor, assignment operator and destructor.
Hope I'm clear enough.

Does the default assignment operator call operator= on all members?

And similarly, does the default copy constructor call the copy constructor on all members? For example, if a class has a non-POD member like so:
class A
{
std::string str;
};
...will the default compiler-generated copy constructor and assignment operator work correctly? Will they call the string's copy constructor and operator= or will they just make a bitwise copy of member variable str?
In other words, does having a std::string member mean this class needs a user-implemented copy constructor and assignment operator?
Yes, the compiler-generated one will work correctly.
However, if you implement your own and leave them empty, it won't.
If you're not managing memory and all your members provide correct copying/assignment/destruction, you don't need (and shouldn't) implement your own copy constructor/destructor/assignment operator.
In other words, does having a std::string member mean this class needs a user-implemented copy constructor and assignment operator?
No, the compiler-generated ones will work perfectly.

C++: Is default copy constructor affected by presence of other constructors and destructor?

As we know, if any constructor is declared (copy constructor included), default constructor (the one that takes no arguments) is not implicitly created. Does the same happen with a default copy constructor (the one that performs shallow copy of an object)? Also, does the presence of destructor affect this anyhow?
12.8 #4 Copying class objects
If the class definition does not
explicitly declare a copy constructor,
one is declared implicitly
And the destructor plays no part
The answers here are correct but not complete. They are correct for C++98 and C++03. In C++11 you will not get a copy constructor if you have declared a move constructor or move assignment operator. Furthermore if you have declared a copy assignment operator or a destructor, the implicit generation of the copy constructor is deprecated. 12.8 [class.copy]:
If the class definition does not
explicitly declare a copy constructor,
there is no user-declared move
constructor, and there is no
user-declared move assignment
operator, a copy constructor is
implicitly declared as defaulted
(8.4.2). Such an implicit declaration
is deprecated if the class has a
user-declared copy assignment operator
or a user-declared destructor.
No. You'll get a default copy constructor unless you supply your own copy constructor, and the presence or absence of a destructor makes no difference.
No. And note that
MyClass
{
template <typename T> MyClass(const T&);
};
does not provide a copy constructor, and a default one is generated.
The default copy constructor is always created, unless you define your own one. The constructor with no arguments isn't defined with any other constructor present to avoid calling it and therefore skipping the real constructor(s)'s code.