-2

The way the code works is that there is a base pure virtual class called "Module" with subclasses of "Living", "Manufacturing" and "PowerGen" which uses some of the virtual functions. In the main driver file, I am successfully able to read a list of modules from a file and store them in a vector of Module pointers. The problem comes when I want to use the virtual display function to display that vectors element's module details. I am faced with a segmentation fault. Any help would be much appreciated!

Class Module
{
public:
   Module() = default;
   explicit Module(const string& purpose, const string& id)
   {
      this->purpose = purpose;
      this->id = id;
   }
   explicit Module(const string& purpose) { this->purpose = purpose; }
   virtual ~Module() { }

   virtual void setCrew( ) = 0;
   virtual void display( ) const = 0;
   void addCrew(const string& name)
   {
      crew_list.push_back(Crew(name));
      ++number_of_crew;
   }
   void setPowerReq(double power) { this->power = power; }
   void setMaxCrew(int max_crew) { this->max_crew = max_crew; }

   string getPurpose( ) { return purpose; }
   string getId( ) { return id; }
   int getNumberOfCrew( ) { return number_of_crew; }
   int getMaxCrew( ) { return max_crew; }
   double getPower( ) { return power; }

   friend ostream& operator << ( ostream& os, const Module& m );
   friend ofstream& operator << ( ofstream& os, const Module& m );
   friend ifstream& operator >> ( ifstream& is, Module& m );

private:
   string purpose = "unknown";
   string id = "unknown";
   int number_of_crew = 0;
   int max_crew = 0;
   double power = 0;
   vector<Crew> crew_list;
}; 


 class Living : public Module
{
public :

   Living( ) = default;
   explicit Living(const string& purpose);
   Living(int meals, const string& id);
   void setCrew( )
   {
      setMaxCrew( floor(meals / 3) );
      setPowerReq( meals * 1.4 );
   }
   void display( ) const
   {
      cout << *this;
   }

   friend ofstream& operator << ( ofstream& os, const Living& l );
   friend ifstream& operator >> ( ifstream& is, Living& l );

private :
   int meals = 0;
   static string type;
};

class Manufacturing : public Module
{
public:
   Manufacturing( ) = default;
   Manufacturing( const string& product, int quantity, const string& id );
   explicit Manufacturing( const string& purpose );
   void setCrew( )
   {
      setPowerReq( quantity * 6 );
      setMaxCrew( maxCrew );
   }
   void display( ) const
   {
      cout << *this;
   }

   friend ofstream& operator << ( ofstream& os, const Manufacturing& m );
   friend ifstream& operator >> ( ifstream& is, Manufacturing& m );

private:
   static string type;
   string product = "unknown";
   static int maxCrew;
   int quantity = 0;
};

class PowerGen : public Module
{
public:
   PowerGen() = default;
   PowerGen( int number_of_generators, const string& id );
   explicit PowerGen( const string& purpose );
   void setCrew( )
   {
      setMaxCrew(0);
      setPowerReq( -(number_of_generators * 7) );
   }
   void display( ) const
   {
      cout << *this;
   }

   friend ofstream& operator << ( ofstream& os, const PowerGen& p );
   friend ifstream& operator >> ( ifstream& is, PowerGen& p );

private:
   static string type;
   const int max_generators = 8;
   int number_of_generators = 0;
};

Portion relevant from the main driver file which when called causes the segmenation fault:

if( cityVector.size() > 0 )
   {
      cout << "\nHere is the complete City" << endl;
      for ( auto iter : cityVector )
      {
         iter->display( );
         cout << endl << endl;
      }
   } else {
      cout << "\nThere are no Modules in the City" << endl;
   }

This is how I loaded the data from a file, where VMOD = vector:

void load( VMOD & cityVector )
{
   string filename;
   cout << "Please enter a filename >> ";
   getline( cin, filename );
   ifstream fin;
   fin.open(filename);
   if (!fin.fail())
   {
      while ( !fin.eof() )
      {
         string purpose;
         getline( fin, purpose );
         if ( purpose == "Living" )
         {
            Living object(purpose);
            loadObject( cityVector, object, fin );
          } else if ( purpose == "Manufacturing" )
         {
            Manufacturing object(purpose);
            loadObject( cityVector, object, fin );
         } else if ( purpose == "Power Generation" )
         {
            PowerGen object(purpose);
            loadObject( cityVector, object, fin );
         } else {

         }
      }
      cout << "The city has " << cityVector.size() << " modules!" << endl;
   } else {
      cout << "File does not exist... " << endl;
   }
   fin.close();
}

template<typename T>
void loadObject( VMOD & cityVector, T object, ifstream& fin )
{
   fin >> object;
   Module* mptr;
   mptr = &object;
   cityVector.push_back(mptr);
}

With the file looking like this:

Living
L1
5
21
2
First Person
Fourth Person
15
Manufacturing
M1
10
12
4
Second Person
Third Person
Fifth Person
Sixth Person
C++ ness
2
Power Generation
P1
0
-14
0
2
Hatted Rooster
  • 33,170
  • 5
  • 52
  • 104
  • The right tool to solve such problems is your debugger. You should step through your code line-by-line *before* asking on Stack Overflow. For more help, please read [How to debug small programs (by Eric Lippert)](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). At a minimum, you should \[edit] your question to include a [Minimal, Complete, and Verifiable](http://stackoverflow.com/help/mcve) example that reproduces your problem, along with the observations you made in the debugger. – πάντα ῥεῖ Oct 09 '16 at 06:39
  • The culprit, most likely, is the code you use to save the objects to the file and to read them from the file. Please post a [mcve]. – R Sahu Oct 09 '16 at 06:42
  • You have all of these classes, yet you failed to show us anything that instantiates and exercises any of these classes. – PaulMcKenzie Oct 09 '16 at 06:42
  • 1) What is `cityVector`? 2) You shouldn't place `using namespace std;` in header files. – PaulMcKenzie Oct 09 '16 at 06:50
  • cityVector is a vector of Module pointers. I do have namespace std in the header files. – Alex Neumann Oct 09 '16 at 06:52
  • You should not be having `using namespace std;` in header files. There are plenty of links saying why this is not a habit to get into. Please [read this](http://stackoverflow.com/questions/4872373/why-is-including-using-namespace-into-a-header-file-a-bad-idea-in-c) – PaulMcKenzie Oct 09 '16 at 06:54
  • You need to read [this, about `eof`](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong). – molbdnilo Oct 09 '16 at 06:56
  • Don't vandalise your post – Hatted Rooster Oct 10 '16 at 07:51

1 Answers1

0

You have a dangling pointer problem.

template<typename T>
void loadObject( VMOD & cityVector, T object, ifstream& fin )
{
   // object is a function local object
   // since it is passed by value.
   fin >> object;
   Module* mptr;

   // This is a pointer to a local object.
   // It is invalid when the function returns.
   mptr = &object;

   // Storing a pointer that will be a dangling pointer as soon
   // the function returns.
   cityVector.push_back(mptr);
}

You need to use dynamically allocated memory for the restored objects and save them in cityVector.

You'll need to make sure that memory is deallocated once you are done using it.

template<typename T>
void loadObject(VMOD& cityVector, ifstream& fin )
{
   T* objectPtr = new T;
   fin >> *objectPtr;
   cityVector.push_back(objectPtr);
}

and call it using the following syntax:

loadObject<LivingObject>(cityVector, fin);
R Sahu
  • 196,807
  • 13
  • 136
  • 247