This question already has answers here:
Copy constructor elision?
(2 answers)
Closed 8 years ago.
class A
{
public:
A ()
{
wcout << L"Empty constructed." << endl;
}
A (LPCWSTR Name)
: m_Name(Name)
{
wcout << L"Constructed." << endl;
}
friend void swap (A& Lhs, A& Rhs)
{
using std::swap;
swap(Lhs.m_Name, Rhs.m_Name);
}
A (A&& Other)
{
wcout << L"Move constructed." << endl;
swap(*this, Other);
}
A (const A& Other)
: m_Name(Other.m_Name)
{
wcout << L"Copy constructed." << endl;
}
A& operator= (A Other)
{
wcout << L"Assignment." << endl;
swap(*this, Other);
return *this;
}
~A ()
{
wcout << L"Destroyed: " << m_Name.GetString() << endl;
}
private:
CString m_Name;
};
int
wmain ()
{
A a;
a = A(L"Name"); // Where is the construction of this temp object?
return 0;
}
This is the output I get for the above code:
Empty constructed.
Constructed.
Assignment.
Destroyed:
Destroyed: Name
See the line with the comment. What I expected is for a temp object to get constructed there, and the argument Other in the operator= would get move-constructed from that temp-object. What's happening here?
The output that says "Constructed" is actually the feedback from the construction of that temporary object.
If you are looking for an additional copy-construction (or move-construction) of Other parameter of copy-assignment operator, it was probably eliminated by copy elision. Your A(L"Name") is immediately constructed and used as that Other parameter. No extra copying (or moving) is performed.
You can use an interactive debugger to see for yourself. However, your answer to where "Name" got constructed is this:
A (LPCWSTR Name)
: m_Name(Name)
{
wcout << L"Constructed." << endl;
}
and
a = A(L"Name");
Your code constructed an empty object at the code line A a;.
It then constructed "Name".
Then it swapped the two's CString m_Name; (shown by the output Assignment).
Then it destructed the original object holding "Name" (A(L"Name")).
Then it destructed the original empty object that is now holding "Name" in its m_Name.
Related
I would like to fully understand move semantics in C++11. So I have written a couple of classes to see when different constructors are called:
#include <iostream>
using namespace std;
class A {
public:
A() : a1_(0) {std::cout << "Calling constructor" << std::endl;}
A(A&& other) {
std::cout << "Calling move constructor" << std::endl;
a1_ = other.a1_;
other.a1_ = 0;
}
// Move assignment operator.
A& operator=(A&& other) {
std::cout << "Calling move operator" << std::endl;
if (this != &other) {
a1_ = other.a1_;
other.a1_ = 0;
}
return *this;
}
// Copy constructor.
A(const A& other) {
std::cout << "Calling copy constructor" << std::endl;
a1_ = other.a1_;
}
// Copy assignment operator.
A& operator=(const A& other) {
std::cout << "Calling copy assignment operator" << std::endl;
if (this != &other) {
a1_ = other.a1_;
}
return *this;
}
private:
int a1_;
};
class B {
A oA_;
public:
B() {}
void setoA(A a) {oA_ = a;}
A getoA() {return oA_;}
};
A createA() {
A a1;
return a1;
}
B createB() {
B tmpB;
A tmpA;
tmpB.setoA(tmpA);
return tmpB;
}
int main() {
B b;
A a;
b.setoA(a);
std::cout << "**************************" << std::endl;
b.setoA(createA());
std::cout << "**************************" << std::endl;
b.setoA(std::move(createA()));
std::cout << "**************************" << std::endl;
B b2;
b2.setoA(b.getoA());
std::cout << "**************************" << std::endl;
createB();
return 0;
}
When I check the output of this code:
Calling constructor
Calling constructor
Calling copy constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling move constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling copy constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling constructor
Calling copy constructor
Calling copy assignment operator
I have some doubts here:
I thought that if you pass r-value, move constructor will be called, is that right? Isn't this b.setoA(createA()); an r-value?
How can I make move constructor/operator being called?
First of all in first section, why is constructor being called twice?
Because you construct both an B and a A with the former having its own instance of A, which the first (the unexpected) constructor call comes from.
I thought that if you pass r-value move constructor will be called, is that right? Isn't this b.setoA(createA()); an r-value?
The constructor is called from within createA (and yes, return value is an r-value), however, copy elision occurs and the object is directly instantiated in the parameter variable of setoA.
Within setoA, however, the copy assignment is selected, as now a is an l-value. If you want to move, you need:
void setoA(A a) { oA_ = std::move(a); }
Some copies and moves may be optionally elided by the compiler. To prevent this, use -fno-elide-constructors in GCC and Clang. In addition, some move elisions became mandatory in C++17, so to force the compiler to use C++11 move semantics, use -std=c++11 as well.
I have the following code:
template<class T = char>
class String
{
public:
// Default constructor
String()
: buffer(nullptr),
len(0)
{
cout << "Default constructor" << endl;
}
// Constructor
String(const char* s)
{
cout << "Constructor (const char*)" << endl;
//...
}
// Virtual destructor.
virtual ~String()
{
cout << "Destructor" << endl;
len = 0;
delete[] buffer;
}
// Copy constructor
String(const String& s)
{
cout << "Copy constructor" << endl;
buffer = new T[s.len];
std::copy(s.buffer, s.buffer + s.len, buffer);
len = s.len;
}
// Copy assignment operator (uses copy and swap idiom)
String& operator=(String s)
{
cout << "Copy assignment operator (copy and swap idiom)" << endl;
std::swap(buffer, s.buffer);
return *this;
}
// Move constructor
String(String&& s)
{
cout << "Move constructor" << endl;
}
// compound assignment (does not need to be a member,
// but often is, to modify the private members)
String& operator+=(const String& rhs)
{
cout << "operator+=" << endl;
//...
return *this; // return the result by reference
}
// friends defined inside class body are inline and are hidden from non-ADL lookup
// passing lhs by value helps optimize chained a + b + c
// otherwise, both parameters may be const references
friend String operator+(String lhs, const String& rhs)
{
cout << "operator+" << endl;
lhs += rhs; // reuse compound assignment
return lhs; // return the result by value (uses move constructor)
}
private:
T* buffer;
size_t len;
};
int main()
{
String<> s("Hello ");
String<> s2("World");
// call copy constructor first?
String<> s3 = s + s2;
return 0;
}
And the output is:
Constructor (const char*)
Constructor (const char*)
Copy constructor
operator+
operator+=
Move constructor
Destructor
My question is why is the copy constructor called immediately in:
String<> s3 = s + s2;
A value copy of s is taken by friend String operator+(String lhs, const String& rhs), essentially because s is not an anonymous temporary and is therefore not an appropriate candidate for move construction. Taking that value copy requires the copy constructor.
To my understanding, the copy constructor is called to receive the return value of the + operator.
This is my code:
#include <iostream>
using namespace std;
class A
{
int i;
public:
A(int v) : i(v) { }
A(const A& r) : i(r.i) {
cout << "Copy constructor" << endl;
}
A operator=(const A& r) {
cout << "Assignment function" << endl;
return r;
}
void show() {
cout << i << endl;
}
};
int main()
{
A a(1);
A b(2);
a = b;
a.show();
return 0;
}
Value of b is 2 and value of a is 1. In 'main', b is copied into a and this the output I get:
Assignment function
Copy constructor
This is understandable, but the output for a.show() comes out be 1. I can't understand this. How? Because b is copied into a using the copy constructor so shouldn't a.i have the value of b.i?
b is copied into a using the assignment operator, not the copy constructor. And your assignment operator doesn't assign i, so a.i keeps its original value.
The copy constructor you are seeing is for the return value of operator=. It is more customary to return the left-hand-side by reference, not the right-hand-side by value:
A& operator=(const A& r) {
cout << "Assignment function" << endl;
i = r.i;
return *this;
}
When you define the assignment operator you have to do all of the work to copy the data.
A operator=(const A& r) {
cout << "Assignment function" << endl;
i = r.i;
return r;
}
so a = b is calling your assignment operator (obviously, hence your output). But right now it isn't copying anything.
The assignment operator doesn't do anything to the "assigned to" object. The copy constructor call you see reported is from the creation of the assignment return value.
Your copy assignment should probably look loke this:
A& A::operator= (A const& other) {
// output
this->i = other.i;
return *this;
}
I would like to print the id of my object when the object is being evaluated (third line in my main function "one = two; should output "Object id: 2"). I know that the assignment operator is only invoked for the lvalue, a conversation operator to itself will never be called and I don't want to use the function call operator.
Any ideas how this can be done, which operator must I overload?
P.S.: Please ignore any saneness of the code, I only care about identifying the right to-be-overloaded operator.
#include <iostream>
class Object
{
public:
Object( int id ) : id_( id )
{
}
//Assignment operator only invoked for lvalue
Object& operator= (const Object& other)
{
std::cout << "Object id: " << id_ << std::endl;
return *this;
}
//Conversion operator to itself will never be called
operator Object() const
{
return *(this);
}
//Function call operator - not what I mean
Object operator()()
{
std::cout << "Object id: " << id_ << std::endl;
return *(this);
}
private:
int id_;
};
int main()
{
Object one(1);
Object two(2);
one = two;
one = two();
return 0;
}
The concept of "object evaluation" isn't really present in C++. An expression can be evaluated, of course, and operator overloading fits into this: foo = bar invokes any overloaded operator= which matches the operands (and in the case of operator= specifically, must be a member of the LHS class type). But it's the assignment that's being evaluated, not foo or bar (and note that in the context of the operator overload, these are present as pointers or references, so it's not inevitable that either one will be evaluated at all).
The appropriate solution here will depend on what it is you're trying to accomplish. But there's no one function that automatically fires whenever your code mentions bar.
#include <iostream>
class Object
{
public:
Object( int id ) : id_( id )
{
}
//Assignment operator only invoked for lvalue
Object& operator= (const Object& other)
{
std::cout << "Object id: " << other.id_ << std::endl;
return *this;
}
private:
int id_;
};
int main()
{
Object one(1);
Object two(2);
one = two;
return 0;
}
I tried this to see if Mat was right, turns out it compiles and prints "Object id: 2" as expected.
So, this line:
one = two;
Will call this function that you already have:
Object& operator= (const Object& other)
{
std::cout << "Object id: " << id_ << std::endl;
return *this;
}
However, let's note that there are two Object objects that are visible in that function.
Object& operator= (const Object& other)
{
std::cout << "Object(" << this->id_ << ")";
std::cout << " = ";
std::cout << "Object(" << other.id_ << ")";
std::cout << "\n";
return *this;
}
You can see a full example where we run this code at ideone.com.
I have a user-defined class (tree structure) with implemented move semantics, and a swap function. I would like to implement a move function the proper way, working as standard std::move implementation.
In the tree node class, each child node has a parent pointer, pointing to the parent node. This means that for move operations, all children have to reparented (and there may be many children)
This means that use of swap for moving is not optimal, as children of both lists have to be reparented after being swapped. So I would like to implement a move function which clears the moved-from tree.
The declaration of std::move implementations is somewhat complicated, they use a std::remove_reference<T>::type&& return type. Do I need this?
You don't need to write a specialisation of std::move.
If you write a correct move constructor and move assignment operator, std::move will work on your class.
example:
#include <iostream>
#include <cstring>
using namespace std;
struct Thing {
Thing()
: _data(new int[100])
{
cout << "default construct\n";
}
// Copy operator
Thing(const Thing& other)
: _data(new int[100])
{
cout << "copy constructor\n";
memcpy(_data, other._data, sizeof(int) * 100);
}
// Move constructor
Thing(Thing&& other) noexcept
: _data(other._data)
{
cout << "move constructor\n";
other._data = nullptr;
}
// assignment operator
Thing& operator=(const Thing& rhs) {
cout << "copy operator\n";
if (&rhs != this) {
Thing tmp(rhs);
std::swap(*this, tmp);
}
return *this;
}
// move assignment operator
Thing& operator=(Thing&& rhs) noexcept {
cout << "move operator\n";
std::swap(_data, rhs._data);
return *this;
}
// destructor necessary since we are working in dangerous new/delete territory
~Thing() noexcept {
cout << "destructor " << (_data ? "object has data" : "object is empty") << "\n";
delete[] _data;
}
private:
int* _data;
};
int main()
{
cout << "constructing a\n";
Thing a;
cout << "constructing b with copy of a\n";
Thing b(a);
cout << "moving a to newly constructed c\n";
Thing c(std::move(a));
cout << "moving c back to a\n";
a = std::move(c);
cout << "create a new d\n";
Thing d;
cout << "replace d with a copy of a\n";
d = a;
return 0;
}
Program's output:
constructing a
default construct
constructing b with copy of a
copy constructor
moving a to newly constructed c
move constructor
moving c back to a
move operator
create a new d
default construct
replace d with a copy of a
copy operator
copy constructor
move constructor
move operator
move operator
destructor object is empty
destructor object has data
destructor object has data
destructor object is empty
destructor object has data
destructor object has data
To write move semantics is to write move constructor/move assignment, but not to implement move function. As result, you maybe move the root of the another tree in move ctor/assignment.
class binary_tree_node {};
class binary_tree
{
public:
binary_tree() : root(nullptr) {}
binary_tree(binary_tree &&rhs)
: root(rhs.root)
{
rhs.root = nullptr;
}
binary_tree& operator=(binary_tree rhs)
{
swap(rhs);
return *this;
}
void swap(binary_tree &rhs)
{
std::swap(root, rhs.root);
}
private:
binary_tree_node *root;
};
int main()
{
binary_tree tree1;
binary_tree tree2 = std::move(tree1);
return 0;
}