简体   繁体   中英

C++,runtime error: member call on null pointer of type

First of all, I am new here to c++ and I'm trying to learn it. Also new to stackoverflow. Find it quite hard to be honest. If you have additional comments in terms of my code and how i can improve it, please let me know as I am still in the learning process.

ok I was I just creating a online booking system using object oriented programming.

Ok so the main issue is that I dont understand why system.setDisplay(1234); isn't printing anything. I have tried everything and just isn't adding up. OnlineBookingSystem is the class is being used to call setDisplay(id) which then invoked the display class. If you can help it would mean the world to me and the error i`m getting is:

runtime error: member call on null pointer of type 'User' (solution.cpp) SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:179:54

#include <vector>
#include <string>
#include <iostream>
#include <memory>
#include <queue>
using namespace std;

enum class BookGenre
{
    Horror,Adventure,Romance,Comic
};
class Book
{
    private:
        BookGenre genre;
        string title;
        size_t id;
    public:
        Book(string title,size_t id,BookGenre genre):title(title),id(id),genre(genre){}
        string getTitle(){return title;}
        size_t getId(){return id;}
        BookGenre getGenre(){return genre; }
};
class Library
{
    private:
        vector<shared_ptr<Book>> listOfBooks;
    public:
        Library(){};
        void addBook(string title,size_t id,BookGenre genre)
        {
            listOfBooks.push_back(make_shared<Book>(title,id,genre));
        }
        shared_ptr<Book> getBook(size_t id)
        {
            for(auto&x:listOfBooks)
            {
                if(x->getId()==id)
                {
                    return x;
                }
            }
            return nullptr;
        }
        void removeBook(size_t id)
        {
            for(auto it=listOfBooks.begin();it!=listOfBooks.end();it++)
            {
                if((*it)->getId()==id)
                {
                    listOfBooks.erase(it);
                }
            }
        }
};
class User
{
    protected:
        size_t id;
        string username;
     
    public:
        User(size_t id,string username):id(id),username(username)
        {
 
        }
        virtual ~User(){}
        size_t getId(){return id;}
        string getUsername(){return username;}

};
class Employee:public User{
    private:
        double salary;
    public:
        Employee(size_t id,string username,double salary):User(id,username),salary(salary)
        {
        }
        void setSalary(double salary)
        {
            this->salary=salary;
        }
        double getSalary(){return salary;}
     
};
class Customer:public User{
    private:
           bool membership;
    public:
        Customer(size_t id,string username):User(id,username)
        {
            membership=false;
        }
        void setMemberActive()
        {
            membership=true;
        }
        bool isMemberActive()
        {
            return membership;
        }
};
class UserManager
{
    private:
        vector<shared_ptr<User>>listOfUsers;
        queue<shared_ptr<Customer>>queue;
    public:
        UserManager()
        {

        }
      
        void addCustomer(size_t id,string username)
        {
            listOfUsers.push_back(make_shared<Customer>(id,username));
        }
        void removeCustomer(string username)
        {
            for(auto it=listOfUsers.begin();it!=listOfUsers.end();it++)
            {
                if(dynamic_pointer_cast<Customer>(*it))
                {
                    if((*it)->getUsername()==username)
                    {
                        listOfUsers.erase(it);
                    }
                }
            }
        }
        shared_ptr<Customer> getCustomer(string username)
        {
            for(auto it=listOfUsers.begin();it!=listOfUsers.end();it++)
            {
                if(dynamic_pointer_cast<Customer>(*it))
                {
                    if((*it)->getUsername()==username)
                    {
                        return dynamic_pointer_cast<Customer>(*it);
                    }
                }
            }
            return nullptr;
        }
        void addToQueue(string username)
        {
            queue.push(getCustomer(username));
        }
        void removeCurrentCustomer()
        {
            queue.pop();
        }
        shared_ptr<Customer> getNextCustomer()
        {
            if(queue.empty())
            {
                return nullptr;
            }
            return queue.front();
        }
        /*
            same process for user;
        */
};
class Display
{   
    private:
        shared_ptr<Customer> m_customer;
        shared_ptr<Book> m_book;
    public:
        Display(shared_ptr<Customer> _customer,shared_ptr<Book> _book ):m_customer(_customer),m_book(_book)
        {

        }
        shared_ptr<Customer> getUser(){return m_customer;}
        shared_ptr<Book> getBook(){return m_book;}
        void displayInfo()
        {
            cout<<"Customer username: "<<m_customer->getUsername()<<endl;
            cout<<"Member Active: "<<m_customer->isMemberActive();
            cout<<"book id: "<<m_book->getId()<<endl;
            cout<<"book title: "<< m_book->getTitle()<<endl;
        }

};
class OnlineBookingSystem
{
    private:
        UserManager manager;
        Library library;
        shared_ptr<Display>display;
    public:
        OnlineBookingSystem()
        {
            UserManager manager;
            Library library;
            this->manager=manager;
            this->library=library;
            this->display=nullptr;
        }
        Library getLibrary()
        {
            return library;
        }
        UserManager getUserManager()
        {
            return manager;
        }
        void  setDisplay(size_t id)
        {
            display=make_shared<Display>( manager.getNextCustomer(),library.getBook(id));
            display->displayInfo();
        }
        shared_ptr<Display> getDisplay()
        {
            return this->display;
        }
};
int main()
{

    OnlineBookingSystem system;
    auto lib=system.getLibrary();
    lib.addBook("Adventure of Pablo",1234,BookGenre::Adventure);
    auto manager=system.getUserManager();
    manager.addCustomer(2020,"Michael");
    auto _customer=  manager.getCustomer("Michael");
    _customer->setMemberActive();
    manager.addToQueue("Michael");
    system.setDisplay(1234);

    return 0;
}

Problems I see:

Problem 1

Since the return type of OnlineBookingSystem::getLibrary() is Library , the line

auto lib=system.getLibrary();

construct lib as a copy of the object in system . Any changes made to lib are changes to the copy, not to the Library object in system .

To fix the problem, change the return type to a reference:

Library& getLibrary()
{
    return library;
}

and capture the return value also as a reference in main .

auto& lib=system.getLibrary();

Problem 2

Similar to Problem 1 but this time it is in OnlineBookingSystem::getUserManager . Change its return type to be a reference:

UserManager& getUserManager()
{
    return manager;
}

and capture the return value also as a reference in main .

auto& manager=system.getUserManager();

Problem 3

Adopt defensive programming at every step until something is a performanced bottleneck. If a return value of a function can be nullptr , check the return value at the point of invocation and deal with the case when the return value is indeed nullptr .

Update OnlineBookingSystem::setDisplay to:

    void  setDisplay(size_t id)
    {
        display=make_shared<Display>( manager.getNextCustomer(),library.getBook(id));
        if ( display )
        {
            display->displayInfo();
        }
        else
        {
           // Deal with the nullptr case
           std::cout << "Unable to find a book with id " << id << std::endl;
        }
    }

The problem
It comes down to your call to system.getUserManager() returning a copy of OnlineBookingSystem 's manager field, instead of a pointer to it.

As a result, when you call manager.addToQueue("Michael") , it is adding Michael to the UserManager instance that is local to int main() , instead of the instance that's held in system .

Your function OnlineBookingSystem::setDisplay(size_t) makes a call to manager.getNextCustomer() . Because you've added Michael to a different instance of manager , this returns nullptr .

How to fix it
You simply need to modify OnlineBookingSystem::getUserManager() to return a pointer to manager instead of a copy of it:

UserManager* getUserManager()
{
    return &manager;
}

Then modify the calling code to use the pointer dereference operator ( -> ) instead of a period to access methods on manager .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM