Related questions:
Why this move constructor is not called wtih rvalue temporary? [duplicate]
Move Constructor vs Copy Elision. Which one gets called?
move Constructor is not called
I'm posting this question because this thing of the move semantics is really puzzling me. At first they seemed quite clear to me, but when I tried to demostrate the use of those to myself, then I realized that maybe I've misunderstood something.
I've tried to arrange the following file to be a not-so-trivial implementation of a vector-like class making use of move semantics (actually the main function is there as well, together with a free function to make printing to screen easier, ...). It is not really a minimal working example, but the output it produces to screen is reasonably readable, imho.
Still, if you thing it's better to slim it down, please suggest me what to do.
Anyway the code is the following,
#include<iostream>
using namespace std;
int counter = 0; // to keep count of the created objects
class X {
private:
int id = 0; // hopefully unique identifyier
int n = 0;
int * p;
public:
// special member functions (ctor, dtor, ...)
X() : id(counter++), n(0), p(NULL) { cout << "default ctor (id " << id << ")\n"; }
X(int n) : id(counter++), n(n), p(new int[n]) { cout << "param ctor (id " << id << ")\n"; };
X(const X& x) : id(counter++), n(x.n), p(new int[n]) {
cout << "copy ctor (id " << id << ") (allocating and copying " << n << " ints)\n";
for (int i = 0; i < n; ++i) {
p[i] = x.p[i];
}
};
X(X&& x) : id(counter++), n(x.n), p(x.p) {
cout << "move ctor (id " << id << ")\n";
x.p = NULL;
x.n = 0;
};
X& operator=(const X& x) {
cout << "copy assignment (";
if (n < x.size() && n > 0) {
cout << "deleting, ";
delete [] p;
n = 0;
}
if (n == 0) {
cout << "allocating, and ";
p = new int[n];
}
n = x.size();
cout << "copying " << n << " values)";
for (int i = 0; i < n; ++i) {
p[i] = x.p[i];
}
cout << endl;
return *this;
};
X& operator=(X&& x) {
this->n = x.n;
this->p = x.p;
x.p = NULL;
x.n = 0;
cout << "move assignment (\"moving\" " << this->n << " values)\n";
return *this;
};
~X() {
cout << "dtor on id " << id << " (array of size " << n << ": " << *this << ")\n";
delete [] p;
n = 0;
}
// getters/setters
int size() const { return n; }
// operators
int& operator[](int i) const { return p[i]; };
X operator+(const X& x2) const {
cout << "operator+\n";
int n = min(x2.size(), this->size());
X t(n);
for (int i = 0; i < n; ++i) {
t.p[i] = this->p[i] + x2.p[i];
}
return t;
};
// friend function to slim down the cout lines
friend ostream& operator<<(ostream&, const X&);
};
int main() {
X x0;
X x1(5);
X x2(5);
x1[2] = 3;
x2[3] = 4;
cout << "\nx0 = x1 + x2;\n";
x0 = x1 + x2;
cout << "\nX x4(x1 + x2);\n";
X x4(x1 + x2);
cout << x4 << endl;
cout << '\n';
}
// function to slim down the cout lines
ostream& operator<<(ostream& os, const X& x) {
os << '[';
for (int i = 0; i < x.size() - 1; ++i) {
os << x.p[i] << ',';
}
if (x.size() > 0) {
os << x.p[x.size() - 1];
}
return os << ']';
}
When I compile and run it with
$ clear && g++ moves.cpp && ./a.out
the output is the following (#-comments are added by hand)
default ctor (id 0)
param ctor (id 1)
param ctor (id 2)
x0 = x1 + x2;
operator+
param ctor (id 3)
move assignment ("moving" 5 values)
dtor on id 3 (array of size 0: [])
X x4(x1 + x2);
operator+
param ctor (id 4)
[0,0,3,4,0]
dtor on id 4 (array of size 5: [0,0,3,4,0])
dtor on id 2 (array of size 5: [0,0,0,4,0])
dtor on id 1 (array of size 5: [0,0,3,0,0])
dtor on id 0 (array of size 5: [0,0,3,4,0])
From the first part of the output, I guess that I really demonstrated the intended use of the move assignment operator. Am I right, in this respect? (From the next output, it seems I'm not, but I'm not sure.)
At this point, if my deduction that copy elision prevented the call to the copy ctor is right, then one question comes natural to me (and not only me, see OP's comment here):
Isn't that situation of creating an object based on another temporary object (e.g. x4 based on the result of x1 + x2 in X x4(x1 + x2);) exactly the one for which move semantics where supposed to be introduced? If not, what is a basic example to show the use of the move ctor?
Then I read that copy elision can be prevented by adding a proper option.
The output of
clear && g++ -fno-elide-constructors moves.cpp && ./a.out
however, is the following:
default ctor (id 0)
param ctor (id 1)
param ctor (id 2)
x0 = x1 + x2;
operator+
param ctor (id 3)
move ctor (id 4)
dtor on id 3 (array of size 0: [])
move assignment ("moving" 5 values)
dtor on id 4 (array of size 0: [])
X x4(x1 + x2);
operator+
param ctor (id 5)
move ctor (id 6)
dtor on id 5 (array of size 0: [])
move ctor (id 7)
dtor on id 6 (array of size 0: [])
[0,0,3,4,0]
dtor on id 7 (array of size 5: [0,0,3,4,0])
dtor on id 2 (array of size 5: [0,0,0,4,0])
dtor on id 1 (array of size 5: [0,0,3,0,0])
dtor on id 0 (array of size 5: [0,0,3,4,0])
+enrico:CSGuild$
where it looks like the call to the move ctor I expect is now there, but both that call and the call to the move assignment are preceded by another call to the move ctor each.
Why is this the case? Have I completely misunderstood the meaning of move semantics?
You appear to have two questions here:
why is the move constructor not called for X x4(x1 + x2)?
why, when copy elision is disabled, is the move constructor called twice?
The first question
Isn't that situation (X x4(x1 + x2);) exactly the one for which move
semantics where supposed to be introduced?
Well, no. In order to use move semantics you're effectively suggesting that we should choose to construct an X in operator+, and then move it to the result x4, which is clearly inefficient compared to a copy-elided construct the final result (x4) in place during operator+.
The second question
Having disabled copy-elision, why do we see two calls to the move constructor during X x4(x1 + x2)? Consider that there are three scopes in play here:
the operator+ scope, where we construct an X and return it;
the main scope where we are calling X x4(x1 + x2);
the X constructor where we are constructing an X from x1 + x2;
Then, in the absence of elision, the compiler is:
moving the result from operator+ to main (into x1 + x2); and
moving the content of x1 + x2 into x4.
Related
In c++ you can swap 2 numbers without 3rd variable:
int x = 10;
int y = 5;
x ^= y;
y ^= x;
x ^= y; //x = 5, y = 10
So I wonder if there is a similar way to swap 2 structs without 3rd variable:
struct Position{int x, y;};
int main()
{
Position firstPose{x = 10, y = 5;};
Position secPose{x = 5, y = 10;};
//Now I want to swap firstPose with secPose.
}
Is this possible? if so; how to do it
There is no a standard way to swap two structure without an intermediate copy. Arguably, one of the main benefit of swap "is" the intermediate copy, this wonderful article explain how swap is a crucial part to achieve "strong exception guarantee". https://www.stroustrup.com/except.pdf
Furthermore, if the goal is to not make a copy of the struct (because is resource intensive) you can design your class using the pimpl idiom and swap just the pointer (you will still have a third variable but it will be just the raw pointer to the structure).
If you want to use C++ effectively make yourself familiar with exception safety, it is truly of of the area where the language gives its best
A bit old but still good article: http://www.gotw.ca/gotw/008.htm
At the end, the final solution is create a custom swap function:
#include <iostream>
#include <string>
struct Position{int x, y;};
void swap(Position& a, Position& b)
{
a.x ^= b.x;
b.x ^= a.x;
a.x ^= b.x;
a.y ^= b.y;
b.y ^= a.y;
a.y ^= b.y;
}
int main()
{
Position a = { 10, 100};
Position b = { 20, 200};
swap(a, b);
std::cout << "a:" << a.x << "," << a.y << std::endl;
std::cout << "b:" << b.x << "," << b.y << std::endl;
}
IMHO, the last option is more for personal amusement than real production code.
Yes, there are some ways to achieve your requirement. But, note that the XOR method of swapping between two values is quite inefficient.
First of all, let's assume the required struct:
struct position {
int x;
int y;
};
Method 1
Create your own swap() function:
void swap(position &pos1, position &pos2) {
// Swapping X
verify_overflow(pos1.x, pos2.x); // See about this below
pos1.x = pos1.x + pos2.x;
pos2.x = pos1.x - pos2.x;
pos1.x = pos1.x - pos2.x;
// Swapping Y
verify_overflow(pos1.y, pos2.y); // See about this below
pos1.y = pos1.y + pos2.y;
pos2.y = pos1.y - pos2.y;
pos1.y = pos1.y - pos2.y;
}
Now, you can implement it like this:
swap(v1, v2);
Note: To prevent undefined-behavior due to the overflows, the following subroutine could be used:
inline void verify_overflow(signed int si_a, signed int si_b) {
signed int sum;
if (__builtin_sadd_overflow(si_a, si_b, &sum)) {
std::cerr << "[error] Overflow is possible to happen.\n";
exit(1);
}
}
For example, when you set a struct:
position v1 = {2147483647, 2147483644};
The program will yield the following error, then UB won't occur:
[error] Overflow is possible to happen.
Method 2
There is already a built-in std::swap() in C++ standard. Its benefit is that you won't need to keep changing the code when the struct alters. The code should look like this:
#include <iostream>
struct position {
int x;
int y;
};
int main(void) {
position v1 = {5, 10};
position v2 = {10, 5};
std::swap(v1, v2);
std::cout << v1.x << ' ' << v1.y << std::endl;
std::cout << v2.x << ' ' << v2.y << std::endl;
return 0;
}
I have written this class and driver function:
#include <cstdlib>
#include <iostream>
using namespace std;
class Weight {
int grams;
int kilograms;
public:
Weight(int kg, int g) : kilograms(kg), grams(g) {
}
~Weight() {
cout << "Destructor " << this->kilograms << " " << this->grams << "\n";
}
friend Weight operator+(const Weight& a, const Weight& b);
Weight operator+(const Weight& w) const {
cout << "member operator+\n";
int newKg = this->kilograms + w.kilograms;
int newG = this->grams + w.grams;
if (newG >= 1000) {
newG -= 1000;
newKg += 1;
}
return Weight(newKg, newG);
}
Weight operator+(const int addition) const {
cout << "operator+int" << endl;
int newKg = this->kilograms;
int newG = this->grams + addition;
if (newG >= 1000) {
newG -= 1000;
newKg += 1;
}
return Weight(newKg, newG);
}
Weight operator+(const double addition) const {
cout << "operator+double" << endl;
int newKg = this->kilograms + ((int) addition);
int newG = this->grams + (1000 * (addition - ((int) addition)));
if (newG >= 1000) {
newG -= 1000;
newKg += 1;
}
return Weight(newKg, newG);
}
Weight& operator=(const Weight & w) {
cout << "Assignment operator\n";
this->grams = w.grams;
this->kilograms = w.kilograms;
return *this;
}
void print() {
cout << "Weight is: " << this->kilograms << " Kilograms and " << this->grams <<
" Grams\n";
}
};
Weight operator+(const Weight& a, const Weight& b) {
cout << "Friend plus\n";
int newKg = a.kilograms + b.kilograms;
int newG = a.grams + b.grams;
if (newG >= 1000) {
newG -= 1000;
newKg += 1;
}
return Weight(newKg, newG);
}
int main(int argc, char** argv) {
Weight m(90, 900);
m = m + 1.1;
m = m + m;
m.print();
return 0;
}
And here is the output:
operator+double
Assignment operator
Destructor 92 0
Friend plus
Assignment operator
Destructor 184 0
Weight is: 184 Kilograms and 0 Grams
Destructor 184 0
Why the destructor was called twice after the two assignment operators were called? (i.e., third and sixth lines in the output).
I know these are probably for the temporary variable being used for the addition, but what is the rule or C++ specification for this?
Thanks.
Because indeed the operator+ creates a temporary object which is the result of the operation, and is discarded after the assignment.
Consider your own signature for the operator+: Weight operator+(const double addition) const. This returns, by value, a Weight object instance. This isn't a reference, nor a pointer. It's a de-facto new object that is created to hold the result of m + 1.1, without updating the value of m first (unlike operator+=). This is even more evident from a look in your own code: return Weight(newKg, newG); - a new object is created right here, and it needs to be destroyed.
This temporary value is then assigned into m, and the temporary object is then destroyed as it moves out of scope.
As a side note, what you see here is also an optimization (a standard optimization called "return value optimization") as the explicit behavior for this situation would've been the construction of the temporary value in the return statement inside the stack frame of the operator+, followed by a copy-construction of the value in the stack frame of the calling function main and then the destruction of the object in the operator+ stack frame. Then the value in main would've gone into the assignment operator, and then destroyed too. Your compiler just optimized this code to construct the return value directly on the stack frame of the calling function saving an extra temporary object.
For one of our class assignments we had to implement a polynomial class. It stores the coefficients of a polynomial and outputs the answer.
In my class definition, I have a friend operator that outputs the function:
friend std::ostream& operator << (std::ostream& out, Polynomial& p);
and my implementation is as follows:
std::ostream& operator << (std::ostream& out, Polynomial& p) {
double ans = 0;
for(int i = 0; i <= p.order; ++i)
ans += (double)p.coefficents[i] * pow(p.x, i);
out << ans;
return out;
}
My main function (written by my instructor) is:
int main ()
{
Polynomial p1 (0.5,3); // Invokes two argument constructor for p1
p1.inputCoefficients(); // Set the coefficient of polynomial p1
cout << "Polynomial p1 evaluates to " << p1 << endl;
Polynomial p2(p1), p3; // Copy constructor for p2 and default constructor for p3
cout << "Polynomial p2 evaluates to " << p2 << endl;
cout << "Polynomial p3 evaluates to " << p3 << endl;
p3 = p2; // Copy assignment operator
return 0;
}
My question is:
When I run my program with this line of code:
double ans = 0;
my output is this:
Polynomial p1 evaluates to 1.375
Polynomial p2 evaluates to 1.375
Polynomial p3 evaluates to 0
Polynomial destroyed!
Polynomial destroyed!
Polynomial destroyed!
Which is the correct output
but if I change that line to this:
double ans;
Unexpected things start to happen:
Polynomial p1 evaluates to 1.375
Polynomial p2 evaluates to 1.375
Polynomial p3 evaluates to 1.375
Polynomial destroyed!
Polynomial destroyed!
Polynomial destroyed!
Why is p3 evaluated to 1.375? p3 was created using the default constructor so wouldn't it output 0?
As soon as the polynomial is outputted wouldn't the scope of ans die? Even if it didn't, or ans kept the value from the last time it ran, then wouldn't p2 be doubled (be 2.75) because the << operator ran twice?
Please feel free to get technical and offer advice, I'm curious and want to know the insides of what's actually going on.
Here is the entirety of my code (for reference):
/*
Using dynamic arrays, implement a polynomial class. In mathematics, polynomial is a function of the form f(x) = a0*x^0 + a1*x^1 + a2*x^2 + a3*x^3 + ....n terms. Here, a0, a1, a2 etc. are the coefficients of the polynomial and n is the order of the polynomial.
The private variables include the value of x (a real number), the order of the polynomial (an integer) and the dynamic array that stores the coefficients (real numbers).
The public methods include
a. default constructor that sets the value of x to zero and the order to 0,
b. a two argument constructor that takes as arguments the value of x and the order of the polynomial. The values of the coefficients are set to zero.
c. inputCoefficients(): prompts the user to input the value of the coefficients of the polynomial. For this homework, skip the user input. Instead assign the coefficent values equal to the index of the position in the array. For example, a0 = 0, a1 = 1, a2 = 2 and so on depending on the order of the particular polynomial object
c. a copy constructor
d. << operator overloaded that returns the value of the polynomial (obtained by evaluating the polynomial).
e. == overloaded (copy assignment operator)
f. destructor. Deallocates dynamic arrays and prints a message "Polynomial destroyed! "
Below is the testing program -
*/
#include <iostream>
using std::cin;
using std::endl;
using std::cout;
#include <cmath>
class Polynomial {
public:
Polynomial() {
x = 0,
order = 0;
coefficents = new double[order + 1];
}
Polynomial(const double x, const int order) {
this->x = x;
this->order = order;
this->coefficents = new double[order + 1];
for(int i = 0; i <= order; ++i)
this->coefficents[i] = 0;
}
Polynomial(const Polynomial& p) {
this->x = p.x;
this->order = p.order;
this->coefficents = new double[this->order];
for(int i = 0; i <= this->order; ++i)
this->coefficents[i] = p.coefficents[i];
}
~Polynomial() {
std::cout << "Polynomial destroyed! " << std::endl;
delete[] coefficents;
}
void inputCoefficients() {
/*
for(auto& num: coefficents) {
std::cout << "Enter the next coefficent:: ";
std::cin >> num;
}
std::cout << "Thank you" << std::endl;
*/
for(int i = 0; i <= order; ++i) {
coefficents[i] = i;
}
}
Polynomial& operator = (const Polynomial& p) {
this->x = p.x;
this->order = p.order;
delete[] this->coefficents;
this->coefficents = new double[order + 1];
for(int i = 0; i <= this->order; ++i)
this->coefficents[i] = p.coefficents[i];
return *this;
}
friend std::ostream& operator << (std::ostream& out, Polynomial& p);
friend bool operator == (const Polynomial& p1, const Polynomial& p2);
private:
double x;
double* coefficents;
int order;
};
std::ostream& operator << (std::ostream& out, Polynomial& p) {
double ans;
for(int i = 0; i <= p.order; ++i)
ans += (double)p.coefficents[i] * pow(p.x, i);
out << ans;
return out;
}
bool operator == (const Polynomial& p1, const Polynomial& p2) {
if((p1.x != p2.x) && (p1.order != p2.order))
return false;
for(int i = 0; i < p1.order; ++i) {
if(p1.coefficents[i] != p2.coefficents[i])
return false;
}
return true;
}
int main ()
{
Polynomial p1 (0.5,3); // Invokes two argument constructor for p1
p1.inputCoefficients(); // Set the coefficient of polynomial p1
cout << "Polynomial p1 evaluates to " << p1 << endl;
Polynomial p2(p1), p3; // Copy constructor for p2 and default constructor for p3
cout << "Polynomial p2 evaluates to " << p2 << endl;
cout << "Polynomial p3 evaluates to " << p3 << endl;
p3 = p2; // Copy assignment operator
return 0;
}
Your << function contains the line:
ans += (double)p.coefficents[i] * pow(p.x, i);
If you don't initialize ans to 0, then the initial value of ans will be indeterminate, and then you're adding each term to this. So you get a random result.
In your case, ans is apparently holding on to its value from the previous call. And since p3 is an empty polynomial, the loop never adds anything to it, so you print the previous result.
I am trying to understand the concept of copy constructor. With copy constructor I get desired result. But with out copy constructor I get the same result. The code is given here:
#include<iostream>
using namespace std;
class Point
{
private:
int x, y;
public:
Point(int x1, int y1) { x = x1; y = y1; }
// Copy constructor
// Point(const Point &p2) {x = p2.x; y = p2.y; }
void set()
{
x=50;
y = 100;
}
int getX() { return x; }
int getY() { return y; }
};
int main()
{
Point p1(10, 15); // Normal constructor is called here
Point p2 = p1 ;
// p2 = p1;
cout << "p1.x = " << p1.getX() << ", p1.y = " << p1.getY();
cout << "\np2.x = " << p2.getX() << ", p2.y = " << p2.getY();
p2.set();
cout << "\np1.x = " << p1.getX() << ", p1.y = " << p1.getY();
cout << "\np2.x = " << p2.getX() << ", p2.y = " << p2.getY();
// Copy constructor is called here
// Let us access values assigned by constructors
return 0;
}
The out put is :
p1.x = 10, p1.y = 15
p2.x = 10, p2.y = 15
p1.x = 10, p1.y = 15
p2.x = 50, p2.y = 100
Shouldn't it be :
p1.x = 10, p1.y = 15
p2.x = 10, p2.y = 15
p1.x = 50, p1.y = 100
p2.x = 50, p2.y = 100
Edit 1 : What if I initialize objects like this:
Point p1(10, 15); // Normal constructor is called here
Point p2(11,10);
p2 = p1;
Will it call copy constructor? If not, why in this case the result is the same?
C++ makes a distinction between objects and references to objects. If you want
p2 and p1 to point to the same Point, you should do this:
Point& p2 = p1;
Because you never defined a copy constructor for your Point class, the compiler gave you one. It will effectively look like this:
Point(const Point& other) : x(other.x), y(other.y)
{}
And your code, Point p2 = p1 will call this copy constructor.
This causes the integer values to be copied, not point to the same location in memory.
But without copy constructor I get the same result.
This is because you get a default copy constructor and a default assignment operator inserted for you by the compiler. It does precisely the same thing as your hand-written copy constructor does, so there is no need to code one manually.
Shouldn't it [the optput] be ...
No, it should not. In your code p1 and p2 are different unrelated objects, even though the initial state of p2 comes from p1.
You need to use pointers or references to get the behavior that you want:
// Point p2 = p1;
Point& p2(p1);
Now p2 behaves as an "alias" for p1, so there is really one object.
demo
A copy constructor is called usually in cases of declaration and initialization of object to another object at same time, or while passing to functions. What the first statement means is:
Point p1(10,15);
Point p2(p1);
Is an example of usage of copy constructor while,
Point p1(10,15);
Point p2;
p2=p1;
is just plain assignment.
And No. Your output is right in the first case. A copy constructor just copies the values of one object into another, it doesn't make the new one a reference object.
Also, the main use of copy constructor is usually in functions.
As a footnote, to understand constructors and when they are called, you could use different cout statements in them. Then you'll know when a particular constructor is called.
P.S. I'm a beginner, so please tell me if I've got anything wrong.
I was reading the Box2D source code. In b2Vec2 there is the () operator being overloaded, but I did not understand what it is supposed to do. I read the manual and the reference of this method but still did not get what it means to Read from an indexed element and write to an indexed element, and both methods have the same body return (&x)[i]. What does this mean and do?
Thanks to a previous comment (but it was removed for some reason), I got an idea and tested it out, and it turns out this will allow me to access and write to x and y using indices 0 and 1 respectively.
For example:
#include <iostream>
using namespace std;
class clazz {
public:
float x, y;
clazz(float x_, float y_) : x(x_), y(y_) {}
float operator () (int i) const {
return (&x)[i];
}
float& operator () (int i) {
return (&x)[i];
}
};
int main() {
clazz f (3, 4);
cout << "f: x = " << f(0) << " y = " << f(1) << endl; // printed => f: x = 3 y = 4
f(0) = 6;
f(1) = 6;
cout << "f: x = " << f(0) << " y = " << f(1) << endl; // printed => f: x = 6 y = 6
return 0;
}
As you found out it's an accessor function to the individual elements in the vector class. The reason there are two functions is due to const functions need access to the value of the element without needing to modify it. Note that you could return a const reference here as well but this is not necessary in your case since it is operating on a float.
Hopefully there are asserts in place for making sure that code isn't indexing out of the range since that is quite easy to do, especially when you have are using a signed variable like in your example.