I'm new here and this is my first question. I have a question about my homework assignment. I'm asked to design an abstract class "Base" which is inherited by the class "Sub" (in the assignment there are sub1, sub2 etc but I have tried to narrow it down as much as possible). Then, I should design a class "BasePtr" which stores a pointer to a "Base" object. Finally, baseptr:s are to be stored in a std::vector, and written to a file using ostream_iterator and copy. The file should then be read with a ifstream_iterator, and stored in a std::list.
I have solved the above problem, but I have some problems when implementing the destructor, copy constructor and assignment operator (since I am dynamically allocating memory in my BasePtr class I believe that those should be present).
This is the main program.
#include 
#include 
#include 
#include 
#include "baseptr.h"
using namespace std;
int main()
{  
    vector basevec;
    basevec.push_back( BasePtr(new Sub(1, 4)) );
    basevec.push_back( BasePtr(new Sub(3, 5)) );
    ofstream os("fil.dat");
    ostream_iterator baseout(os,"\n");
    copy( basevec.begin(), basevec.end(), baseout);
    os.close();
    ifstream is("fil.dat");
    istream_iterator basein(is), endofbasein;
    list baselist(basein, endofbasein );
    for (list::iterator it = baselist.begin(); it != baselist.end(); it++) 
        cout << *it << endl;    
}
     
The BasePtr class
#include 
#include 
#include "base.h"
using namespace std;
class BasePtr {
public: 
    BasePtr() : basevar(0) {}
    BasePtr(Base *bin) {basevar = bin->clone(); delete bin;}
    const BasePtr & operator=( BasePtr & baseptr ); // assignment operator
    BasePtr(const BasePtr &baseptr ); // copy constructor
    ~BasePtr(); // destructor
    friend ostream& operator<<( ostream &os, const BasePtr &baseptr); 
    friend istream& operator>>( istream &is, BasePtr &baseptr); 
private:
    Base* basevar;
};
const BasePtr & BasePtr::operator=( BasePtr & baseptr ) {
    if (this != &baseptr) {
        delete basevar;
        basevar = baseptr.basevar->clone();
    }
    return *this;
}
BasePtr::BasePtr( const BasePtr &baseptr ) {
    if (baseptr.basevar != 0)
        basevar = baseptr.basevar->clone();
}
BasePtr::~BasePtr() {
    if ( basevar != 0 )
        delete basevar;
    basevar = 0;
}
ostream& operator<<( ostream &os, const BasePtr &baseptr) {
    os << *baseptr.basevar;
    return os;
}
istream& operator>>( istream &is, BasePtr &baseptr) {
    string name;
    if (!(is >> name))
        return is;
    Base *b = 0;
    if ( name == "SUB" ) 
        b = new Sub();  
    is >> *b;
    baseptr.basevar = b->clone();
    delete b;
    return is;
}
and the Base and Sub classes
#include 
using namespace std;
class Base {
public: 
    virtual ~Base() {}
    virtual Base* clone() const = 0; 
    friend ostream& operator<<( ostream &os, Base &b) {
        b.print(os); 
        return os;}
    friend istream& operator>>( istream &is, Base &b) {b.readStream(is); return is;}
protected:
    Base(const double xin) : x(xin) {}
    double x;
    virtual ostream& print(ostream &os) const = 0; 
    virtual void readStream( istream &is ) = 0;
};
class Sub : public Base{
public:
    Sub() : Base(0), size(0) {}
    Sub(double xin, double si) : Base(xin), size(si) {}
    ~Sub() {};
    Sub* clone() const {return new Sub(*this);}
private:
    double size;
    Sub(const Sub &p) : Base(p.x), size(p.size) {}
protected:
    virtual ostream& print(ostream &os) const {os << "SUB " <<  x << " " << size << endl; 
        return os; }
    virtual void readStream( istream &is ) {
        is >> x;
        is >> size;
    }
};
If I comment out the destructor, copy constructor and assignment operator the program builds and runs, and outputs the desired result. However, valgrind finds loads of memory leaks (obviously). If I include these functions, the program ends with Segmentation fault: 11. I am using a mac with os x 10.8 and the clang compiler. What am I doing wrong?
Answer
The bug in your program is probably in the copy constructor:
BasePtr::BasePtr( const BasePtr &baseptr ) {
    if (baseptr.basevar != 0)
        basevar = baseptr.basevar->clone();
    else {
        basevar = 0; // <<<< missing
    }
}
Without this change the following code will produce errors:
BasePtr a; // a.basevar = 0
BasePtr b = a; // now b.basevar is not initialized
// destruction of b will call delete on an uninitialized pointer
 
No comments:
Post a Comment