复制构造函数析构函数和赋值运算符,用于存储指向另一个类的指针的类

Copy constructor destructor and assignment operator for class storing pointers to another class

提问人:danieldahlin 提问时间:5/8/2014 更新时间:5/8/2014 访问量:792

问:

我是新来的,这是我的第一个问题。我有一个关于家庭作业的问题。我被要求设计一个抽象类“Base”,它由类“Sub”继承(在赋值中有 sub1、sub2 等,但我试图尽可能地缩小范围)。然后,我应该设计一个类“BasePtr”,它存储指向“Base”对象的指针。最后,baseptr:s 将存储在 std::vector 中,并使用 ostream_iterator 和 copy 写入文件。然后,应使用ifstream_iterator读取该文件,并将其存储在 std::list 中。

我已经解决了上述问题,但是在实现析构函数、复制构造函数和赋值运算符时遇到了一些问题(因为我在我的 BasePtr 类中动态分配内存,我认为这些应该存在)。

这是主要程序。

#include <vector>
#include <fstream>
#include <iterator>
#include <list>
#include "baseptr.h"

using namespace std;
int main()
{  
    vector<BasePtr> basevec;
    basevec.push_back( BasePtr(new Sub(1, 4)) );
    basevec.push_back( BasePtr(new Sub(3, 5)) );

    ofstream os("fil.dat");
    ostream_iterator<BasePtr> baseout(os,"\n");
    copy( basevec.begin(), basevec.end(), baseout);
    os.close();

    ifstream is("fil.dat");
    istream_iterator<BasePtr> basein(is), endofbasein;
    list<BasePtr> baselist(basein, endofbasein );

    for (list<BasePtr>::iterator it = baselist.begin(); it != baselist.end(); it++) 
        cout << *it << endl;    
}

BasePtr 类

#include <iostream>
#include <string>
#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;
}

以及 Base 和 Sub 类

#include <iostream>
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;
    }

};

如果我注释掉析构函数、复制构造函数和赋值运算符,程序就会生成并运行,并输出所需的结果。但是,valgrind 发现了大量内存泄漏(显然)。如果我包含这些函数,程序将以 Segmentation fault: 11 结束。我正在使用带有 os x 10.8 和 clang 编译器的 mac。我做错了什么?

C++ 析构函数 copy-constructor assignment-operator

评论

0赞 Rakib 5/8/2014
您正在将指针与 0 进行比较,并在 中。请改用。destructorcopy-constructornullptr
0赞 Danvil 5/8/2014
@RakibulHasan:这不会有任何区别。

答:

1赞 user657267 5/8/2014 #1

您未在复制构造函数中初始化,请将其更改为以下内容:basevarBasePtr

BasePtr::BasePtr( const BasePtr &baseptr ) : basevar{} {
    if (baseptr.basevar != 0)
        basevar = baseptr.basevar->clone();
}
4赞 Danvil 5/8/2014 #2

程序中的错误可能出在复制构造函数中:

BasePtr::BasePtr( const BasePtr &baseptr ) {
    if (baseptr.basevar != 0)
        basevar = baseptr.basevar->clone();
    else {
        basevar = 0; // <<<< missing
    }
}

如果不进行此更改,以下代码将产生错误:

BasePtr a; // a.basevar = 0
BasePtr b = a; // now b.basevar is not initialized
// destruction of b will call delete on an uninitialized pointer

评论

0赞 danieldahlin 5/8/2014
非常感谢@Danvil,这解决了它。经过十年的 Matlab 编程,C++ 感觉很复杂......
0赞 SChepurin 5/8/2014
@Abhishek Bansal - 记忆泄漏也神秘地消失了?
0赞 Abhishek Bansal 5/8/2014
@SChepurin 可能不是,但 OP 的问题不是内存泄漏。问题是分段错误。
0赞 danieldahlin 5/8/2014
@AbhishekBansal 将文件读入 list<BasePtr> 基列表时,我仍然有一个内存问题。由于我使用 base->clone() 来制作对象的副本,所以我有一个“额外”的基本实例,我认为我应该删除它,但我不确定在哪里。Valgrind 说(摘录)==3444== 1 个块中的 24 个字节肯定在丢失记录 1 中的 1 ==3444== 在 0x4C2B1C7: 运算符 new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3444== by 0x401BA8: Sub::clone() const (base.h:26) ==3444== by 0x40131C: BasePtr::BasePtr(BasePtr const&) (baseptr.h:30)
0赞 Abhishek Bansal 5/8/2014
@danieldahlin 您在代码中多次复制。您必须对其进行剖析以查看泄漏发生的位置。此外,由于您的代码可以分为两部分(写入文件和从文件读取),因此您可以一次检查一个部分。