c++: how does memberwise assignment work? [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How are C array members handled in copy control functions?
If I don't override the operator = of a class, it will use default memberwise assignment.
But what does it mean?
struct A {
int array[100];
};
A a;
A b=a;
No error. How does b copes a'sarray? Normally array_b = array_a is invalid.
Another exampe:
struct A {
vector<int> vec;
};
A a;
A b=a;
How does b copes a'svec? Through assignment(vec_b = vec_a), constructor(vec_b = vector<int>(vec_a)) or other mystery way?

A b=a;
Is not assignment, it is called as Copy Initialization.
The implicitly generated copy constructor is called to create an new object b from the existing object a.
The implicitly generated copy constructor makes a copy of the array member.
For completeness I am going to add here the standard citation from the marked duplicate.
C++03 Standard: 12.8 (Copying class objects)
Each subobject is copied in the manner appropriate to its type:
if the subobject is of class type, the copy constructor for the class is used;
if the subobject is an array, each element is copied, in the manner appropriate to the element type;
if the subobject is of scalar type, the built-in assignment operator is used.

If the members have copy constructors, they get invoked. If not, the default copy constructor does the equivalent of memcpy. See Memberwise Assignment and Initialization.
In the case of non-pointer arrays, each element is copied.

Related

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.

What is the behaviour of compiler generated move constructor?

Does std::is_move_constructible<T>::value == true imply that T has a usable move constructor?
If so, what is the default behaviour of it?
Consider the following case:
struct foo {
int* ptr;
};
int main() {
{
std::cout << std::is_move_constructible<foo>::value << '\n';
foo f;
f.ptr = (int*)12;
foo f2(std::move(f));
std::cout << f.ptr << ' ' << f2.ptr << '\n';
}
return 0;
}
and the output is:
1
0000000C 0000000C
I thought that f.ptr should be nullptr.
So in this case,
Is f2 move constructed ?
If so, shouldn't the rvalue be invalidated?
How can I know if instances of a class can be properly move-constructed (invalidate the old one)?
(I'm using VS11.)
Update
The default behaviour of move constructor is same as a copy constructor, is it correct?
If it's true,
We always expect a move ctor to steal the resources of the moved-from object, while the default one does not behave as expected, so what's the point of having a default move ctor?
How can I know if a class has a custom move constructor (which can be guaranteed to behave properly)?
It seems that foo f2(std::move(f)); calls the copy ctor when I declared one, see:
struct foo {
int* ptr;
foo() {}
foo(const foo& other) {
std::cout << "copy constructed\n";
}
};
int main() {
{
std::cout << std::is_move_constructible<foo>::value << '\n';
foo f;
foo f2(std::move(f));
}
system("pause");
return 0;
}
Now the output is:
1
copy constructed
If foo has a move constructor, then wouldn't foo f2(std::move(f)) call it?
So now my questions is:
How to know if a class has a move ctor, and if it has one, how can I explicitly call it?
What I'm trying to do is…
template<typename T, bool has_move_ctor>
struct MoveAux;
template<typename T>
struct MoveAux<T, true> {
static void doMove(T* dest, T* src) {
new(dest) T(std::move(*src)); //move ctor
}
};
template<typename T>
struct MoveAux<T, false> {
static void doMove(T* dest, T* src) {
new(dest) T(*src); //copy ctor
src->~T();
}
};
template<typename T>
inline doMove(T* dest, T* src) {
MoveAux<T,/*a trait*/>::doMove(dest, src);
}
So I thought std::is_move_constructible<T>::value can be passed to the template, while now I see that this trait only cares if T t(T()) is a valid expression, it may call T::T(const T&).
Now assume that T is a custom class, then I want the above templates to behave like:
If I don't declare a move ctor, I want that template method calls the MoveAux<T,false>::doMove.
If I declared one, I need it calls to MoveAux<T,true>::doMove.
Is it possible to make this work?
does std::is_move_constructible<T>::value == true implies that T has a usable move constructor?
Either a move constructor or a copy constructor. Remember that the operation of copy construction satisfies all the requirements that are placed upon the operation move construction, and some more.
In Standard terms, a MoveConstructible object is one for which the evaluation of the expression:
T u = rv;
makes u equivalent to the value of rv before the construction; the state of rv after being moved-from is unspecified. But since it is unspecified, this means the state could even be identical to the one rv had before being moved from: In other words, u could be a copy of rv.
In fact, the Standard defines the CopyConstructible concept to be a refinement of the MoveConstructible concept (so everything which is CopyConstructible is also MoveConstructible, but not vice versa).
if so, what is the default behaviour of it?
The behavior of an implicitly generated move constructor is to perform a member-wise move of the data members of the type for which it is generated.
Per Parahgraph 12.8/15 of the C++11 Standard:
The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move
of its bases and members. [ Note: brace-or-equal-initializers of non-static data members are ignored. See
also the example in 12.6.2. —end note ]
Moreover:
1 - is f2 move constructed ?
Yes.
2 - if so, shouldn't the rvalue be invalidated?
Moving a pointer is the same as copying it. So no invalidation is going on, neither should it be going on. If you want a move constructor that leaves the moved-from object in a particular state (i.e. sets a pointer data member to nullptr), you have to write your own - or delegate this responsibility to some smart pointer class such as std::unique_ptr.
Notice, that the word "invalidated" is not quite correct here. Move constructors (as well as move assignment operators) are meant to leave the moved-from object in a valid (yet unspecified) state.
In other words, the class invariant needs to be respected - and it should be possible to invoke on a moved-from objects operations that do not have any precondition on its state (usually, destruction and assignment).
does std::is_move_constructible::value == true implies that T has a usable move constructor?
No. It states that you can take an rvalue expression of the object type and construct an object from it. Whether this uses the move constructor or the copy constructor is not relevant to this trait.
is f2 move constructed ?
Yes.
if so, shouldn't the rvalue be invalidated?
No. That's not how movement works.
how can I know if instances of a class can be properly move-constructed(invalidate the old one)?
That is not any definition of "properly move-constructed" that exists. If you want to "invalidate the old one", then you will have to do that yourself.
Move construction generally guarantees nothing about the state of the old object. It will be in a valid but undefined state. Such state very much can be "the same as it was before". Move construction for a pointer is the same as copying the pointer.
If you want to "invalidate" after a move, then you need to write your own move constructor that explicitly does that.
(I'm using VS11)
Then you have no compiler-generated move constructors at all. Not that it would matter, since the move and copy constructors for pointers both do the same thing.
the default behaviour of move constructor is same as a copy
constructor, is it correct? if it's true
No. It's wrong. It's true only for primitives. It's similar to that of copy constructor.
The default generated copy constructor calls the copy constructor of all its members in the declared order
But The default generated move constructor calls the move constructor of all its members in the declared order
Now the next question is, what is the copy/move constructor of the primitives ints floats pointers do?
Answer: They just copy the values (both copy and move constructor)
Note that Visual Studio 2012 / VC++11 does not support compiler generated move constructors; in fact, consider this quote from "C++11 Features in Visual C++ 11" blog post (emphasis mine):
Rvalue references v3.0 adds new rules to automatically generate move
constructors and move assignment operators under certain conditions.
This will not be implemented in VC11, which will continue to follow
VC10's behavior of never automatically generating move
constructors/move assignment operators.
With raw pointers, you have to define move constructors by yourself, manually clearing the old "moved-from" pointer:
class Foo
{
public:
// Move constructor
Foo(Foo&& other)
: m_ptr(other.m_ptr) // copy pointer value
{
// Clear out old "moved-from" pointer, to avoid dangling references
other.m_ptr = nullptr;
}
private:
int* m_ptr;
};
Instead, if you use a smart pointer like std::unique_ptr, move constructor is properly defined, and you can just call std::move:
class Foo
{
public:
// Move constructor
Foo(Foo&& other)
: m_ptr(std::move(other.m_ptr)) // move from other,
// old pointer automatically cleared
{
}
private:
std::unique_ptr<int> m_ptr;
};
With automatically generated move constructors, you don't have to define a custom move constructor explicitly, if member-wise move is OK for you.
n3376 12.8/15
The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move
of its bases and members.
Each base or non-static data
member is copied/moved in the manner appropriate to its type:
— if the member is an array, each element is direct-initialized with the corresponding subobject of x;
— if a member m has rvalue reference type T&&, it is direct-initialized with static_cast(x.m);
— otherwise, the base or member is direct-initialized with the corresponding base or member of x.
if foo has a move constructor, then wouldn't foo f2(std::move(f)) calls it?
You do not get the default move constructor when you supply your copy constructor. Add following line to get it ( and notice the change ).
foo(foo&& ifm)=default;

Value initialization on explicit constructor call in C++? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What do the following phrases mean in C++: zero-, default- and value-initialization?
There are multiple places where people have said that an explicit call to the class constructor results in value initialization [when no used-defined constructors exist] and that this is not done by the default constructor [which is a do-nothing constructor] but is something completely different.
What happens actually if no constructor is called OR What is value initialization in this case ?
Firstly, what happens actually if no constructor is called
A constructor for a class-type is always called when an object is constructed, be it user-defined or compiler-generated. The object is initialized, but the members can remain un-initialized. This makes the second part of the question obsolete.
Second, is there documentation that supports/mentions/explains this behaviour ?
The all-mighty standard.
This is only true for aggregates: Consider this:
struct Holder
{
Aggregate a;
NonAggr n;
Holder(int, char) : a(), n() { }
Holder(char, int) { }
};
Holder h1(1, 'a');
Holder h2('b', 2);
Suppose Aggregate is an aggregate type. Now h1.a is value-initialized, which value-initializes each member, while h2.a is default-initialized, which default-initializes each member. The same holds for the n member, but if NonAggr is a non-aggregate class type, its default constructor will always be called.

Class not having copy constructor issue?

I have a class which does not have copy constructor or operator= overloaded.
The code is pretty big but the issue is around this pseudo-code:
ClassA object1(x,y);
object1.add(z)
myVector.push_back(object1);
//Now when I retrieve from myVector and do add it
// apparently creates another object
myVector.at(index).add(z1);
Like I said it is pseudo-code. I hope it make sense to experts out there!
So, ClassA looks like this (of course not all data members included)
Class ClassA {
private:
int x;
string y;
ClassB b;
vector<int> i;
public:
int z;
}
Since ClassB b is a new data member for this release, is the need of copy constructor now become a must?
Thanks again all of you for responding.
Class ClassB {
private:
vector<ClassC*> c;
Class D
}
Class ClassC {
private:
vector<ClassE*> e;
}
Class ClassD{
private:
vector<ClassF*> f;
}
Then ClassE and ClassF have basic types like int and string.
The new object isn't being created when you retrieve the object using
at(); at() returns a reference to it. The new object is being
created when you do the push_back(). And if you don't have an
accessible copy constructor or assignment operator, you can't put the
object into a vector; officially, it's undefined behavior, but at least
if you use the vector (as you've done here), it will in fact not
compile. Most likely you're getting the compiler generated defaults.
Without seeing the actual object type, it's impossible for us to say
whether they're appropriate; if the object type only contains basic
types and types from the standard library (other than the iostream stuff
and auto_ptr—and the threading stuff if you're using C++11),
then the compiler generated copy constructor and assignment should be
OK. If the class contains pointers to memory you allocate in the
constructor, it almost certainly isn't.
It must create a temporary when retrieving because the value stored is a copy.
I have a class which does not have copy constructor or operator= overloaded.
This does not really matter. Unless you explicitly disable them (declare as private and don't implement in C++03, define as delete in C++11) the compiler will generate one for you.
Now, if you do disable copying of your objects you will realize that you can no longer store them directly in a vector, as the vector will copy the argument internally. You could on the other hand store a (smart) pointer in the container, but this might actually complicate the problem you want solved.
I doubt that it is using a copy constructor, but just plain old struct copy.
myVector.at(index)
returns ClassA in this case, not ClassA &
You should be able to solve this by:
ClassA & refObj = myVector.at(index);
refObj.add(z1);
I put together a little test which had surprising results on Visual Studio.
class Boo {
public:
void add() { a++; }
int a;
};
vector<Boo> v;
Boo b;
b.a = 1;
for (int i=0; i<5; i++) {
v.push_back(b);
}
v[0].add();
v.at(1).add();
Boo & refB = v[2]; refB.add();
refB = v.at(3); refB.add();
Boo & refB2 = v.at(4); refB2.add();
printf("%d %d %d %d %d\n", v[0].a, v[1].a, v[2].a, v[3].a, v[4].a);
Results:
2 2 2 1 2
So the compiler treats:
Boo & refB = v[2]; refB.add();
refB = v.at(3); refB.add();
Differently than:
Boo & refB2 = v.at(4); refB2.add();
But I don't get the original problem (that is, v.at(n).add() is not copying, but passing by reference). Are you sure the following line is copying?
myVector.at(index).add(z1)
Could this be compiler specific? What compiler / OS are you using?
I have a class which does not have copy constructor or operator= overloaded.
In that case, the compiler provides these for you. Quoting the C++ 2003 standard, clause 12.8:
If the class definition does not explicitly declare a copy constructor, one is declared implicitly. … The implicitly-declared copy constructor for a class X will have the form
X::X(const X&) [or] X::X(X&). … The implicitly-defined copy constructor for class X performs a memberwise copy of its subobjects.
and
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. … The implicitly-declared copy assignment operator for a class X will have the form X& X::operator=(const X&) [or] X& X::operator=(X&). … The implicitly-defined copy assignment operator for class X performs memberwise assignment of its subobjects.
The push_back creates a copy as it receives the parameter by value. If you dont want to use a copy constructor define the vector as a vector of pointers to your object, and push a pointer instead.

Why don't i have to overload the assignment operator in c++?

Here is my code:
class Example {
...declarations/definitions...
};
Example operator + (Example e)
{
Example temp;
...do addition...
return temp;
}
//main
void main()
{
Example a(1,2);
Example b(3,4);
Example c;
c = a+b;
}
Now what confuses me is that I had to overload the + operator for it to work with the vectors but how about the equal '=' sign?? I am assigning one vector to another, shouldn't i be overloading it too?? Or is it provided already to us?
Thanks.
The language provides a default operator= for you automatically if your class is default assignable (for example if it has any reference members it won't be assignable without special work by you). All it does is assign the base and each member individually.
From the wikipedia page:
The default version [of the assignment operator] performs a memberwise copy, where each member is copied by its own copy assignment operator (which may also be programmer-declared or compiler-generated).
If you don't declare a copy-assignment operator in your class, then one is implicitly declared for you (and implicitly defined if you ever use it).
The implicit operator will assign each member of your object, if that's possible; otherwise (if some member is a reference, or const, or has a private or deleted copy-assignment operator) you'll get a compile error.
Similarly, if you don't declare a copy constructor, then you'll get an implicit one, which will copy each member. Your code is using that in operator+, to copy both the argument and the return value.
The assignment operator is given by default, along with the copy constructor, and default constructor. It assigns the value of each data member to its corresponding data member in the other object (i.e., shallow copy).
A std::vector? If so, std::vector implements the assignment operator by default. From the manpage:
"Assigns a copy of vector x as the new content for the vector object.
The elements contained in the vector object before the call are dropped, and replaced by copies of those in vector x, if any.
After a call to this member function, both the vector object and vector x will have the same size and compare equal to each other."
edit-one of these days I'm going to submit an answer first!
C++ provides a default copy constructor for you that is used for assignment, it copies the class member by member using their (also possibly default) copy constructors.