c++classconstructordestructor

Compiler behavior regarding class objects I don't understand


I'm a noob and still learning the c++ language. The thing is, doing an exercise from a book, I've come across a compiler behavior I don't understand.

The header file.

// stock10.h -- Stock class declaration with constructors, destructor added

#ifndef STOCK10_H_
#define STOCK10_H_

#include <string>

class Stock
{
private:
    std::string company;
    long shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }
public:
    // two constructors
    Stock(); // default constructor
    Stock(const std::string & co, long n = 0, double pr = 0.0);
    ~Stock(); // noisy destructor
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    void show();
};

#endif

The class implementation.

// stock10.cpp -- Stock class with constructors, destructor added

#include <iostream>
#include "stock10.h"

// constructors (verbose versions)
Stock::Stock() // default constructor
{
    std::cout << "Default constructor called\n";
    company = "no name";
    shares = 0;
    share_val = 0.0;
    total_val = 0.0;
}

Stock::Stock(const std::string & co, long n, double pr)
{
    std::cout << "Constructor using " << co << " called\n";
    company = co;
    if (n < 0)
    {
        std::cout << "Number of shares can’t be negative; "
                  << company << " shares set to 0.\n";
        shares = 0;
    }
    else
        shares = n;
    share_val = pr;
    set_tot();
}

// class destructor
Stock::~Stock() // verbose class destructor
{
    std::cout << "Bye, " << company << "!\n";
}

// other methods
void Stock::buy(long num, double price)
{
    if (num < 0)
    {
        std::cout << "Number of shares purchased can’t be negative. "
                  << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(long num, double price)
{
    using std::cout;
    if (num < 0)
    {
        cout << "Number of shares sold can’t be negative. "
             << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cout << "You can’t sell more than you have! "
             << "Transaction is aborted.\n";
    }
    else
    {
        shares -= num;
        share_val = price;
        set_tot();
    }
}

void Stock::update(double price)
{
    share_val = price;
    set_tot();
}

void Stock::show()
{
    using std::cout;
    using std::ios_base;
    // set format to #.###
    ios_base::fmtflags orig =
        cout.setf(ios_base::fixed, ios_base::floatfield);
    std::streamsize prec = cout.precision(3);
    cout << "Company: " << company
         << " Shares: " << shares << '\n';
    cout << " Share Price: $" << share_val;
    // set format to #.##
    cout.precision(2);
    cout << " Total Worth: $" << total_val << '\n';
    // restore original format
    cout.setf(orig, ios_base::floatfield);
    cout.precision(prec);
}

The main file.

// usestok1.cpp -- using the Stock class
// compile with stock10.cpp

#include <iostream>
#include "stock10.h"

int main()
{
    {
        using std::cout;
        cout << "Using (non default) constructors to create new objects\n";
        Stock stock1("NanoSmart", 12, 20.0); // syntax 1
        stock1.show();
        Stock stock2 = Stock ("Boffo Objects", 2, 2.0); // syntax 2
        stock2.show();

        cout << "Assigning stock1 to stock2:\n";
        stock2 = stock1;
        cout << "Listing stock1 and stock2:\n";
        stock1.show();
        stock2.show();

        cout << "Using a constructor to reset an object\n";
        stock1 = Stock("Nifty Foods", 10, 50.0); // temp object
        cout << "Revised stock1:\n";
        stock1.show();
        cout << "Done\n";
    }
    std::cin.get();
    return 0;
}

As you may have guessed, Stock is the class and I've created non-default constructor and destructor to display messages to see when they "act".

Here's the output from program execution:

Using (non default) constructors to create new objects
Constructor using NanoSmart called
Company: NanoSmart Shares: 12
Share Price: $20.000 Total Worth: $240.00
Constructor using Boffo Objects called
Company: Boffo Objects Shares: 2
Share Price: $2.000 Total Worth: $4.00
Assigning stock1 to stock2:
Listing stock1 and stock2:
Company NanoSmart Shares: 12
Share Price: $20.000 Total Worth: $240.00
Company NanoSmart Shares: 12
Share Price: $20.000 Total Worth: $240.00
Using a constructor to reset an object
Constructor using Nifty Foods called
Bye, NanoSmart! // Why? Shouldn't it be Bye, Nifty Foods?
Revised stock1:
Company: Nifty Foods Shares: 10
Share Price: $50.000 Total Worth: $500.00
Done
Bye, NanoSmart!
Bye, Nifty Foods!

In this specific line:

stock1 = Stock("Nifty Foods", 10, 50.0); // temp object

Shouldn't the compiler:
1. Create a temporary object with the constructor
2. Assign that object to the stock1 object
3. Destroy the temporary object

Shouldn't the message say Nifty Foods instead of NanoSmart?

I don't get it. Any help?


Solution

  • You don't have a assignment operator defined, so if you are using a C++11 compiler, it probably uses the move assignment operator, which swaps the objects and then deletes the new contents of the temp object, which used to be in stock1.

    At least, that is the observed behavior. ecatmur is correct, however, that your class should not have received an implicit move assignment operator. That might of course be a compiler bug.