0

I'm a beginner programmer looking to understand why my objects are being deleted, sometimes even twice. I'm trying to avoid creating them on the heap for this project as that is a more advance topic I will try at a later time.

Whats causing the book1, book2 etc.. objects to be instantly deleted? Also it outputs the same book object being deleted twice in a row sometimes for some reason? The same effect happens when using 'case 3: ' in the switch statement through the menu.

#include <iostream>
#include <vector>

using namespace std;

class Book
{
    public:
        // Constructor Prototype
        Book(string author = "Auth", string title = "Title", string publisher = "Pub", float price = 1.99, int stock = 1);

        // Destructor Prototype
        ~Book();

        // Methods
        string get_title() const
        {
            return title;
        }

    private:
        string author;
        string title;
        string publisher;
        float price;
        int stock;
};

// Constructor definition
Book::Book(string author, string title, string publisher, float price, int stock)
    : author{author}, title{title}, publisher{publisher}, price{price}, stock{stock}
{
    cout << "Book: " << title << " was created." << endl;
}

// Destructor definition
Book::~Book()
{
    cout << "Book: " << title << " has been destroyed." << endl;
}

// Functions
void showMenu();
void getChoice();
void userChoice(int choice);
void showBooks(vector<Book> bookList);

// Global Vector
vector<Book> bookList;

int main()
{
    // Creating Book objects for testing purposes
    Book book1("Marcel Proust", "In Search of Lost Time", "Pub", 14.99, 5);
    Book book2("James Joyce", "Ulysses", "Pub", 25.99, 4);
    Book book3("Miguel de Cervantes", "Don Quixote", "Pub", 35.99, 3);
    Book book4("Gabriel Garcia Marquez", "One Hundred Years of Solitude", "Pub", 100.99, 2);
    Book book5("F. Scott Fitzgerald", "The Great Gatsby", "Pub", 49.99, 1);

    // Pushing book1-5 into the vector of Book objects
    bookList.push_back(book1);
    bookList.push_back(book2);
    bookList.push_back(book3);
    bookList.push_back(book4);
    bookList.push_back(book5);

    while(true)
    {
        showMenu();
        getChoice();
    }

    return 0;
}

void showMenu()
{
    cout << "\tMENU" << endl;
    cout << "1. Purchase Book" << endl;
    cout << "2. Search for Book" << endl;
    cout << "3. Show Books available" << endl;
    cout << "4. Add new Book" << endl;
    cout << "5. Edit details of Book" << endl;
    cout << "6. Exit" << endl;
}

void getChoice()
{
    int choice;
    cout << "Enter your choice (1-6): ";
    cin >> choice;
    userChoice(choice);
}

void userChoice(int choice)
{
    switch(choice)
    {
        case 1:
            cout << "Case 1 called." << endl;
            break;
        case 2:
            cout << "Case 2 called." << endl;
            break;
        case 3:
            cout << "Case 3 called." << endl;
            showBooks(bookList);
            break;
        case 4:
            cout << "Case 4 called." << endl;
            break;
        case 5:
            cout << "Case 5 called." << endl;
            break;
        case 6:
            cout << "Case 6 called." << endl;
            exit(0);
    }
}

void showBooks(vector<Book> bookList)
{
    for (Book bk : bookList)
    {
        cout << "Book: " << bk.get_title() << endl;
    }
}

Edit:

Why does it delete the same object 2-3 times in a row sometimes? output (in this case it was "In Search of Lost Time"):

Book: In Search of Lost Time was created.
Book: Ulysses was created.
Book: Don Quixote was created.
Book: One Hundred Years of Solitude was created.       
Book: The Great Gatsby was created.
Book: In Search of Lost Time has been destroyed.       
Book: In Search of Lost Time has been destroyed.       
Book: Ulysses has been destroyed.
Book: In Search of Lost Time has been destroyed. 
Jason
  • 36,170
  • 5
  • 26
  • 60
Chavon4
  • 5
  • 3
  • 2
    Because you're copying them like crazy and destroying copies. See [Rule of Three](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). – Silvio Mayolo Aug 15 '22 at 01:51
  • ahhh @SilvioMayolo i'll check that out.. so they are being copied and destroyed putting them into the vector? – Chavon4 Aug 15 '22 at 01:57
  • 1
    Consider using emplace_back for directly creating books in place as new vector elements. – Avi Berger Aug 15 '22 at 01:58
  • @AviBerger replaced push_back with emplace_back, same thing.. let me add the output to show ya what im asking.. thank you! – Chavon4 Aug 15 '22 at 02:00
  • 1
    And if you do a lot of books, you may want to do a vector.reserve first, as when vector needs to reallocate it also has to do moves/copies, – Avi Berger Aug 15 '22 at 02:00
  • @AviBerger Roger that, I'll look at that aswell. But why is it deleting "In Search of Lost Time" multiple times in a row? – Chavon4 Aug 15 '22 at 02:03
  • Try a booklist.reserve(5) before placing your 5 items into the vector. It could be the vector reallocating. (oops. error corrected.) – Avi Berger Aug 15 '22 at 02:09
  • 1
    `bookList.emplace_back("Marcel Proust", "In Search of Lost Time", "Pub", 14.99, 5);` instead of the push_back should save making a copy unless the compiler optimizer was good enough able to get rid of it on its own. – Avi Berger Aug 15 '22 at 02:11
  • The multiple deletes at the beginning (and some extra constructs) are probably the vector having to resize itself to hold more items & them copying items from its old buffer to the new one. An adequate reserve beforehand should get rid of those. Using emplace_back and pm100's loop adjustment should then bring you down to 5 constructs and when main exits 5 destructs. – Avi Berger Aug 15 '22 at 02:20
  • @AviBerger It worked! Vector reserve and emplace_back solved my problem. So in reality it was just the vector resizing as well as the vector push back making copies and deleting them! thank you guys – Chavon4 Aug 15 '22 at 02:27
  • 1
    One more thing that i missed: Your showBooks should be taking booklist by const reference. Right now you are making an unneeded copy of the vector when you call showBooks. [Here is a test modification](https://godbolt.org/z/7scY36vxx) – Avi Berger Aug 15 '22 at 02:35

2 Answers2

2

here

for (Book bk : bookList)

you are making copies of Books. Do this instead

 for (Book &bk : bookList)

now you just have a reference

pm100
  • 48,078
  • 23
  • 82
  • 145
0

As per the various suggestions in the comments I have compiled the program to suit your needs. It will work without any unwanted allocations. Changes I made are: 1.Reserving the vector to 5 elements. 2. Emplacement. 3. Passing the vector as a reference to the function and 4. Taking the vector elements as a reference while iteration.

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Book
{
public:
    // Constructor Prototype
    Book(string author = "Auth", string title = "Title", string publisher = "Pub", float price = 1.99f, int stock = 1);

    // Destructor Prototype
    ~Book();

    // Methods
    string get_title() const
    {
        return title;
    }

private:
    string author;
    string title;
    string publisher;
    float price;
    int stock;
};

// Constructor definition
Book::Book(string author, string title, string publisher, float price, int stock)
    : author( author ), title( title ), publisher( publisher ), price( price ), stock( stock )
{
    cout << "Book: " << title << " was created." << endl;
}

// Destructor definition
Book::~Book()
{
    cout << "Book: " << title << " has been destroyed." << endl;
}

// Functions
void showMenu();
void getChoice();
void userChoice(int choice);
void showBooks(vector<Book>& bookList);

// Global Vector
vector<Book> bookList;

int main()
{
    bookList.reserve(5);
    bookList.emplace_back("Marcel Proust", "In Search of Lost Time", "Pub", 14.99f, 5);
    bookList.emplace_back("James Joyce", "Ulysses", "Pub", 25.99f, 4);
    bookList.emplace_back("Miguel de Cervantes", "Don Quixote", "Pub", 35.99f, 3);
    bookList.emplace_back("Gabriel Garcia Marquez", "One Hundred Years of Solitude", "Pub", 100.99f, 2);
    bookList.emplace_back("F. Scott Fitzgerald", "The Great Gatsby", "Pub", 49.99f, 1);

    while (true)
    {
        showMenu();
        getChoice();
    }

    return 0;
}

void showMenu()
{
    cout << "\tMENU" << endl;
    cout << "1. Purchase Book" << endl;
    cout << "2. Search for Book" << endl;
    cout << "3. Show Books available" << endl;
    cout << "4. Add new Book" << endl;
    cout << "5. Edit details of Book" << endl;
    cout << "6. Exit" << endl;
}

void getChoice()
{
    int choice;
    cout << "Enter your choice (1-6): ";
    cin >> choice;
    userChoice(choice);
}

void userChoice(int choice)
{
    switch (choice)
    {
    case 1:
        cout << "Case 1 called." << endl;
        break;
    case 2:
        cout << "Case 2 called." << endl;
        break;
    case 3:
        cout << "Case 3 called." << endl;
        showBooks(bookList);
        break;
    case 4:
        cout << "Case 4 called." << endl;
        break;
    case 5:
        cout << "Case 5 called." << endl;
        break;
    case 6:
        cout << "Case 6 called." << endl;
        exit(0);
    }
}

void showBooks(vector<Book>& bookList)
{
    for (const auto& book : bookList){
        cout << "Book: " << book.get_title() << endl;
    }
}
mmj
  • 139
  • 8