Why object's destructor was called after assignment operation is done - c++

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.

Related

Why I am getting error in this code?? And the error is: expected primary-expression before ‘long’

I am getting error in this code while converting the member data of the class Int to long double in the conversion operators. But I don't understand why this happens?
#include<iostream>
using namespace std;
class Int
{
private:
int number;
public:
Int() : number(0) // no argument constructor
{ }
Int( int i) : number(i) // 1-argument constructor
{ }
void putInt() // display Int
{ cout << number; }
void getInt() // take value from the user
{ cin >> number; }
operator int() // conversion operator ( Int to int)
{ return number; }
Int operator + ( Int a)
{ return checkit( long double (number) + long double (a)) ; } // performs addition of two objects of type Int
Int operator - ( Int a)
{ return checkit(long double (number) - long double (a) ); } //performs subtraction of two objects of type Int
Int operator * (Int a)
{ return checkit( long double (number) * long double (a) ); } // performs multiplication of two objects of type Int
Int operator / (Int a)
{ return checkit( long double (number) / long double (a) ); } // performs division of two objects of type Int
Int checkit( long double answer)
{
if( answer > 2147483647.0L || answer < - 2147483647.0L)
{ cout << "\nOverflow Error\n";
exit(1);
}
return Int ( int(answer));
}
};
int main()
{
Int numb1 = 20;
Int numb2 = 7;
Int result, cNumber;
result = numb1 + numb2;
cout << "\nresult = "; result.putInt(); //27
result = numb1 - numb2;
cout << "\nresult = "; result.putInt(); //13
result = numb1 * numb2;
cout << "\nresult = "; result.putInt(); // 140
result = numb1 / numb2;
cout << "\nresult = "; result.putInt(); // 2
cNumber = 2147483647;
result = numb1 + cNumber; // overflow error
cout << "\nresult = "; result.putInt();
cNumber = -2147483647;
result = numb1 + cNumber; // overflow error
cout << endl;
return 0;
}
In the operator overloading code for the +, -, * and / operators, I am getting errors of:
expected primary expression before 'long'
I don't understand why this happens.
The nature of C++ syntax does not allow type names that consist of more than one word (like long double and unsigned int) to be used in functional casts, as you are attempting to do in the long double (number) and long double (a) expressions. (Just using a plain double type would be OK, though.)
But you really shouldn't be using such casts in a C++ program – they're almost as evil as C-style casts.
Whenever possible, use explicit C++ casts, starting from the 'softest' available option; in your case, static_cast will work for the int to long double conversion as well as any other; so, just change your binary operator functions to forms like the following:
Int operator + (Int a)
{
return checkit(static_cast<long double>(number) + static_cast<long double>(a));
} // performs addition of two objects of type Int

Move constructor and move assignment operator vs. copy elision

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.

Scope of Variable in Friend Operator

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.

2D vector ignores assigned values?

I'm working on a simple class representing polynomials. I store coefficients and equivalent powers of x in 2D vector. The way of assigning certain terms must be as shown in the test file. It equires some operator overloading which i provided. The problem is that it assigns proper coefficients besides last one, additionally every terms has power of x of the first assigned value.
Desired output:
Polynomial p1: 2x^3 + 3.6x + 7x^0
Polynomial p2: 3x^1 + 6x^2 + 1x^4
Actual output:
Polynomial p1: 5x^3 + 2x^3 + 3.6x^3
Polynomial p2: 5x^1 + 3x^1 + 6x^1
Have you got any idea what is the case? I
Polynomials.cpp
double & Polynomials::operator[]( int power_of_x ){
this->coeff_and_power.push_back(5.0); // dummy variable 5.0 just to alloc 'cell' for coefficient
this->coeff_and_power.push_back( (double) power_of_x ); //assigning power of x
this->polynomial_terms.push_back( coeff_and_power ); // polynomial_terms vector contains collection of 2 elements vectors( coefficient and power ) indicating certain term of a function
return (coeff_and_power[0]); //coefficient to be assigned in main(returning by reference) function
}
std::ostream& operator<<(std::ostream& out, const Polynomials & toWrite){
for(unsigned int i = 0; i < toWrite.polynomial_terms.size(); i++){
if(i){
out<<" + ";
}
out<<toWrite.polynomial_terms[i][0]<<"x^"<<toWrite.polynomial_terms[i][1];
}
return out;
}
test.cpp
#include <iostream>
#include "Polynomials.h"
using namespace std;
int main(void) {
Polynomials p1;
p1[3] = 2; p1[1] = 3.6; p1[0] = 7;
Polynomials p2;
p2[1] = 3; p2[2] = 6; p2[4] = 1;
cout << "Polynomial p1: " << p1 << endl;
cout << "Polynomial p2: " << p2 << endl;
}
In your operator[] overload you push_back(), but unconditionally.
return coeff_and_power[0];
return front for assignment
And btw this
this->polynomial_terms.push_back( coeff_and_power )
pushes a copy, not a reference, given polynomial_terms has behavior like e.g. std:vector.

for loop doesn't execute

I've written a naive (only accepts integer exponents) power function for complex numbers (a home made class) using a simple for loop that multiplies the result for the original number n times:
C pow(C c, int e) {
C res = 1;
for (int i = 0; i==abs(e); ++i) res=res*c;
return e > 0 ? res : static_cast<C>(1/res);
}
When I try to execute this, e.g.
C c(1,2);
cout << pow(c,3) << endl;
I always get 1, because the for loop doesn't execute (I checked).
Here's the full code:
#include <cmath>
#include <stdexcept>
#include <iostream>
using namespace std;
struct C {
// a + bi in C forall a, b in R
double a;
double b;
C() = default;
C(double f, double i=0): a(f), b(i) {}
C operator+(C c) {return C(a+c.a,b+c.b);}
C operator-(C c) {return C(a-c.a,b-c.b);}
C operator*(C c) {return C(a*c.a-b*c.b,a*c.b+c.a*b);}
C operator/(C c) {return C((a*c.a+b*c.b)/(pow(c.a,2)+pow(c.b,2)),(b*c.a - a*c.b)/(pow(c.a,2)+pow(c.b,2)));}
operator double(){ if(b == 0)
return double(a);
else
throw invalid_argument(
"can't convert a complex number with an imaginary part to a double");}
};
C pow(C c, int e) {
C res = 1;
for (int i = 0; i==abs(e); ++i) {
res=res*c;
// check wether the loop executes
cout << res << endl;}
return e > 0 ? res : static_cast<C>(1/res);
}
ostream &operator<<(ostream &o, C c) { return c.b ? cout << c.a << " + " << c.b << "i " : cout << c.a;}
int main() {
C c(1,2), d(-1,3), a;
cout << c << "^3 = " << pow(c,3) << endl;}
What you wrote will read as follows:
for (int i = 0; i == abs(e); ++i)
initialize i with 0 and while i is equal to the absolute value of e (i.e. 3 at the beginning of the function call), do something
It should rather be
for (int i = 0; i < abs(e); ++i)
Tip: the code will throw at the first iteration due to the double conversion operator (and caused by a*c.b + c.a*b), but this is another issue: fix your complex (i.e. with imaginary part) printing function or implement a pretty printing method or such.
you should be using i != abs(e) or i < abs(e) as for loop condition. Currently you are using i == abs(e) which will fail in first try because:
i = 0
abs(e) = 3
so 0 == 3 is false and hence for loop will not execute.