I'm studying the 'move semantics' introduced since C++11. I wrote a sample code for creating class objects using normal constructors, a copy constructor, and a move constructor.
/* Useless.cpp */
#include <iostream>
using namespace std;
// interface
class Useless {
private:
int n; // number of elements
char* pc; // pointer to data
static int ct; // number of objects
void ShowObject() const;
public:
Useless();
explicit Useless(int k);
Useless(int k, char ch);
Useless(const Useless & f); // regular copy constructor
Useless(Useless && f); // move constructor
~Useless();
Useless operator+(const Useless & f) const;
void ShowData() const;
};
int Useless::ct = 0;
Useless::Useless() {
++ct;
n = 0;
pc =nullptr;
cout << "default constructor called; number of objects" << ct << endl;
ShowObject();
}
Useless::Useless(int k) : n(k) {
++ct;
pc = new char[n];
cout << "int constructor called; number of objects: " << ct << endl;
ShowObject();
}
Useless::Useless(int k, char ch) : n(k) {
++ct;
pc = new char[n];
for (int i=0; i< n; i++) {
pc[i] = ch;
}
cout <<"int, char constructor called; number of objects: " << ct << endl;
ShowObject();
}
Useless::Useless(const Useless & f) : n(f.n) {
++ct;
pc = new char[n];
for (int i =0; i< n; i++) {
pc[i] = f.pc[i]; // deep copy
}
cout << "copy const called; number of objects: " << ct << endl;
ShowObject();
}
Useless::Useless(Useless && f) : n(f.n) {
++ct;
pc = f.pc; // steal address (shallow copy)
f.pc = nullptr;
f.n = 0;
cout << "move const called; number of objects: " << ct << endl;
ShowObject();
}
Useless::~Useless() {
cout << "destructor called; objects left: " << --ct << endl;
cout << "deleted object:\n";
ShowObject();
delete [] pc;
}
Useless Useless::operator+(const Useless & f) const {
cout << "Entering operator+() \n";
Useless temp = Useless (n+f.n);
for (int i=0; i < n; i++) {
temp.pc[i] = pc[i]; // copy the current object's characters
}
for (int i=n; i < temp.n; i++) {
temp.pc[i] = f.pc[i-n]; // copy the argument object's characters
}
cout << "temp object:\n";
cout << "leaving operator+()\n";
return temp;
}
void Useless::ShowObject() const {
cout << "Number of elements: " << n;
cout << "Data address: " << (void *) pc << endl;
}
void Useless::ShowData() const {
if (n==0) {
cout << "(object empty)";
}
else {
cout << "data: ";
for (int i = 0; i < n; i++) {
cout << pc[i] ;
}
}
cout << endl;
}
int main() {
Useless one (10, 'x');
Useless two = one; // call the copy constructor
Useless three(20, 'o');
Useless four(one+three); // it should call operator+() and then the move constructor
cout << "object one: ";
one.ShowData();
cout << "object two: ";
two.ShowData();
cout << "object three: ";
three.ShowData();
cout << "object four: ";
four.ShowData();
return 0;
}
I expected the code generates five Useless
objects (i.e., object 'one', 'two' 'three', a temporary object made by operator+() function, and the object 'four' created by calling the move constructor). However, the result is different from my expectation. The actual result was as follow:
int, char constructor called; number of objects: 1
Number of elements: 10Data address: 0x56230b195eb0
copy const called; number of objects: 2
Number of elements: 10Data address: 0x56230b1962e0
int, char constructor called; number of objects: 3
Number of elements: 20Data address: 0x56230b196300
Entering operator+()
int constructor called; number of objects: 4
Number of elements: 30Data address: 0x56230b196320
temp object:
**leaving operator+()**
object one: data: xxxxxxxxxx
object two: data: xxxxxxxxxx
object three: data: oooooooooooooooooooo
object four: data: xxxxxxxxxxoooooooooooooooooooo
destructor called; objects left: 3
deleted object:
Number of elements: 30Data address: 0x56230b196320
destructor called; objects left: 2
deleted object:
Number of elements: 20Data address: 0x56230b196300
destructor called; objects left: 1
deleted object:
Number of elements: 10Data address: 0x56230b1962e0
destructor called; objects left: 0
deleted object:
Number of elements: 10Data address: 0x56230b195eb0
My expectation was the program generates the fifth object (object 'four') by calling the move constructor defined above (with the result of 'one + three' as input argument). I would appreciate any clue for understanding the result.
Aucun commentaire:
Enregistrer un commentaire