Does the default assignment operator call operator= on all members? - c++

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.

Related

Should std::move be used on members when initializing them in the constructor?

I've been trying to fully understand move semantics, but I have one question, as different examples show different things. Say we have a class Foo that has a string member str_. To define the move constructor, should I define it like this:
Foo(Foo&& foo) : str_(foo.str_) { }
or this:
Foo(Foo&& foo) : str_(std::move(foo.str_)) { }
Also, would I need to set the members of the object i am moving from to a blank value? How would I do so without constructing another string, essentially nullifying the expense saved by using a move constructor in the first place?
You should use the second approach.
You do not have to do anything to the string you move from, because this is handled by string's move constructor. The latter is invoked by the move() call.
The same goes for your own classes, anything you want to move() should have a move constructor. For instance, if your class has a pointer member, your move constructor could/should assign nullptr to that member in the object you move() from.
In a move constructor (or move assignment operator), you need to use std::move() when moving individual members (or at least, on non-POD members, since "moving" a POD type is the same as copying it).
In Foo&& foo, foo is an rvalue reference, but foo.str_ is not. If you call str_(foo.str_) in your move constructor (or str_ = foo.str_ in your move assignment operator), it will call the string's copy constructor (or copy assignment operator). So you need to cast foo.str_ to an rvalue reference via std::move() in order to invoke the string's move constructor (or move assignment operator).
A move constructor (and move assignment operator) is responsible for leaving the moved-from object in an unspecified but valid state, so its destructor will not fail. In the case of moving the foo.str_ member, the string's move constructor (or move assignment operator) will reset foo.str_ to an empty string for you, you do not need to reset it manually.

can I use std::move with class that doesn't provide a move constructor?

I have a class like this:
class myClass
{
int x[1000];
public:
int &getx(int i)
{
return x[i];
}
}
Please note that I did not provide a move construct here.
if I use the following code:
myClass A;
auto B=std::move(a);
does A moves to B or since I did not provided a move constructor, A is copied to B?
Is there any default move constructor for an object? If yes, how it does work with pointers and dynamically allocated arrays?
Although you did not provide explicit move constructor, the compiler provided implicit move constructor to you.
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, and
X does not have a user-declared copy assignment operator,
X does not have a user-declared move assignment operator,
X does not have a user-declared destructor, and
the move constructor would not be implicitly defined as deleted.
So the answer on your question is: no, A is not copied to B.
It is not clear what you ask in other questions. Please specify more details.
Is there any default move constructor for an object?
Yes in your case. For any type T, a move constructor is implicitly declared only if some conditions are met. More details can be seen at cpperference.com.
If yes, how it does work with pointers and dynamically allocated arrays?
The default implementation will make a shallow copies of pointers. As a consequence, more than one object will point to dynamically allocated arrays. That is going lead to problems. See The Rule of Three for more on the subject.
If you have pointers that point to dynamically allocated arrays, you need to:
Provide an explicitly defined copy constructor that does the right thing with the dynamically allocated arrays. The side effect of this will be that the default move constructor will be implicitly deleted. and/or
Provide an explicitly defined move constructor where you move the ownership of the dynamically allocated arrays appropriately.
Move constructor is generated for your class as you don't define any method which avoid its generation (as user defined destructor or copy constructor)
The auto generated move constructor would move each member. For int[1000] it is equivalent to copy.
If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:
There are no user-declared copy constructors.
There are no user-declared copy assignment operators.
There are no user-declared move assignment operators.
There are no user-declared destructors
then the compiler will declare a move constructor as a non-explicit inline public member of its class with the signature T::T(T&&).
Quote from cppreference
Basically, yes a default move constructor is created as long as you don't define a copy constructor, copy assignment overload, move assignment overload, or destructor. Otherwise you have to either define the behavior yourself or use:
class_name ( class_name && ) = default;
which will explicitly declare the default version of the move constructor.
Your question is similar to this one. Note that std::move simply is a cast. Your value a will be cast to an rvalue reference, but in your case, the original object will not be plundered or pilfered.
To use an API or an idiom correctly, you have to use it for the right thing. Moving makes most sense for e.g. class objects where the bulk of the object data is allocated on the heap. Such an object is easy to pilfer, and the 'move' can leave the pilfered object in a well-defined state. The canonical example could be e.g. some type of string class with string data on the heap.
In your case, what would you like to happen? Assume a is a local var in some function, i.e. assume a is on the stack. Assume b is a global or file scope or anonymous namespace variable, i.e. not on the stack. What would you like to happen when moving from a to b?
For a string, pilfering makes sense. For your case, pilfering is nonsensical.

Passing argument of object without copy constructor?

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.

C++ Copy constructor does not copy

I'm trying to initialize one object into other object using copy constructor. I'm puzzled that if I comment out copy constructor it initializes fine but with following code it does not.
class TDateTime : public TData {
public:
TDateTime() : TData(EDataStateInvalid) {}
TDateTime(const tm& aTm){};
TDateTime(int aTm_sec, int aTm_min, int aTm_hour,
int aTm_mday, int aTm_mon, int aTm_year, int aTm_wday,int aTm_isdst){
value.tm_sec=aTm_sec;
value.tm_min=aTm_min;
value.tm_hour=aTm_hour;
value.tm_mday=aTm_mday;
value.tm_mon=aTm_mon;
value.tm_year=aTm_year;
value.tm_wday=aTm_wday;
value.tm_isdst=aTm_isdst;
};
virtual ~TDateTime() {cout<<"Destroying TDateTime ";};
//! Copy constructor
TDateTime(const TDateTime& aInstance){};
//! Copies an instance
virtual const TDateTime& operator=(const TDateTime& aInstance){return *this;};
private:
tm value;
};
main.cpp
tm=createDateTime(x);
TDateTime aDateTimeFrom(tm.tm_sec,tm.tm_min,tm.tm_hour,tm.tm_mday,tm.tm_mon,tm.tm_year,tm. tm_wday,0);
TDateTime aDateTimeTo(aDateTimeFrom);
if I comment out the copy constructor it copies fine. If I remove {} then compiler complains about undefined symbol.
Can you suggest what is wrong here?
Based on answer about empty copy constructor does nothing, I comment it out and copy is perfect but I have another problem. If I do
TDateTime aDateTime;
aDateTime=aDateTimeFrom;
aDateTime has all junk values. Any pointers on this?
//! Copy constructor
TDateTime(const TDateTime& aInstance){};
Your copy constructor does nothing. There is no magic involved with user-written copy constructors; if you don't make them do anything, then they will not do anything.
More precisely, a new instance is created, but its members are left uninitialised or are default-initialised.
While we're at it...
//! Copies an instance
virtual const TDateTime& operator=(const TDateTime& aInstance){return *this;};
Same problem here. Your copy-assignment operator does not do anything.
By convention, it should also not return a const reference but a non-const one.
It may be worth the mention that your intution seems to be correct, as your goal should indeed be to create classes which don't require any self-written copy constructors or copy-assignment operators because all members know how to correctly copy or copy-assign themselves (like std::string or std::vector or std::shared_ptr). But in that case, rather than defining the member functions with empty implementations, you just don't declare them at all in your code, such that the compiler can handle everything automatically.
And finally, one other thing: A good rule of thumb for C++ classes is that they should either have virtual functions and disable copying (sometimes called "identity classes") or have no virtual functions and allow copying (sometimes called "value classes"). Something like a virtual assignment operator often indicates an overly complicated, hard-to-use and error-prone class design.
A compiler generates a copy constructor which performs member-wise copy if the user hasn't declared a copy constructor. If the user does declare a copy-constructor, then the copy constructor does what the user has told it to, in your case - exactly nothing.
TDateTime(const TDateTime& aInstance){ /* empty body*/};
Your define a copy constructor which does not do anything.
In your case you don't really need a copy constructor and/or copy assignment operator, the compiler generated versions would be enough (it would be wise to make sure/recheck that tm class can handle the copying).
There is a rule of three, which states that one needs copy constructor and copy assignment operator if one defines a destructor. But it is only a rule of thumb and not an actual necessity. In your case there is no memory management involved and you use the destructor only for logging.
So do not declare a copy constructor at all (your assign operator has the same flaw by the way - it does not copy anything) and let the compiler do the work.

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.