如何返回没有指针的动态结构?

时间:2013-10-26 12:54:45

标签: c++ dynamic destructor

我必须为两个动态容器重载'+'运算符。

Occurance Occurance::operator +(const Occurance& occ) const {
    Occurance* result = new Occurance;
    Iterator i1(head);
    Iterator i2(occ.head);
    while( !(i1.isNULL() && i2.isNULL()) ) {
        if(i1.getCount() >= i2.getCount()) {
            result->add(i1.getFile());
            result->tail->count = i1.getCount();
            ++i1;
        }
        else {
            result->add(i2.getFile());
            result->tail->count = i2.getCount();
            ++i2;
        }
    }
    return *result;
}

当我这样做时:

Occurance occ = occ1+occ2;

列表开头的指针被正确复制,一切正常,但我失去了对结果的引用。当调用occ析构函数时,整个列表被销毁,但不是结果的第一个元素,因为我只是复制了它的内容而不是引用。

当我将返回类型更改为引用时,在分配期间会发生相同的情况。

另一个想法是不动态创建'结果',因此它在函数结束时自动销毁,但随后它调用了破坏整个列表的析构函数。

是否有任何简单且“正确”的方法来创建此类结构并在没有此内存泄漏的情况下返回它?当然,返回的类型必须是“+”运算符所期望的对象或引用。

我已经想出了一个令人讨厌的黑客,涉及在析构函数中更改指向函数的指针,但也许我只是错过了一些非常简单的东西?

编辑: 当然,课程遵循三个规则。这是作业:

Occurance& Occurance::operator =(const Occurance& occ) {
    destruct();
    head = occ.head;
    current = occ.current;
    tail = occ.tail;
    return *this;
}

Occurance::Occurance(const Occurance& occ) {
    head = occ.head;
    current = occ.current;
    tail = occ.tail;
}

Occurance::~Occurance() {
    destruct();
}

destruct只会破坏以'head'开头的列表。

班级声明:

class Occurance {
private:
    class Node {
    public:
        Node* next;
        Node* prev;
        int count;
        const File* file;

        Node(const File& a_file, Node* a_prev);
    };

    Node* head;
    Node* tail;
    Node* current;
    void destruct();
public:
    class Iterator {
    private:
        Node* node;
    public:
        Iterator();
        Iterator(Node* a_node);
        void operator ++();
        const File& getFile();
        int getCount();
        bool isNULL();
    };

    Occurance();
    Occurance(const Occurance& occ);
    void add(const File& a_file);
    Occurance& operator =(const Occurance& occ);
    Occurance operator +(const Occurance& occ) const;   //dodaje listy zachowując sortowanie
    Iterator begin() const;
    virtual ~Occurance();
};

3 个答案:

答案 0 :(得分:0)

  

另一个想法是不动态创建'结果',因此它在函数结束时自动销毁,但随后它调用了破坏整个列表的析构函数。

您应该阅读有关复制构造函数的信息。在调用返回对象的析构函数之前,将调用复制构造函数,该构造函数将该对象中的数据复制到将保存occ1 + occ2操作结果的临时对象。我假设您有成员指向动态分配的数据,在这种情况下,当调用复制构造函数时,它会将指针分配给临时对象,而不是分配新内存和复制数据。您必须自己编写代码。我建议你阅读:http://www.cplusplus.com/articles/y8hv0pDG/

另请注意,如果要执行此分配,则应以相同方式重载operator =

  

occ = occ1 + occ2

编辑:对不起,我无法发表评论,您是否也可以复制您的课程声明?

答案 1 :(得分:0)

在C ++中,一般原则是在堆栈上返回副本,而不是在堆上分配的对象。所以在这种情况下你只需要:

Occurance Occurance::operator +(const Occurance& occ) const 
{
    Occurance result;
    // do whatever
    return result; 
}

并称之为:

Occurance occ = occ1+occ2;

编译器非常聪明,可以理解不要复制,而是重新使用您要返回的对象(这称为返回值优化或RVO)。

如果您确实需要将对象作为在函数内部创建的完全相同的对象,那么您可以:返回智能指针(查找shared_ptr)或使用新的C ++ 11 { {3}}

答案 2 :(得分:0)

您的复制构造函数和赋值运算符已损坏。您需要对列表进行深层复制,或者需要实现某种共享语义(例如引用计数)。您似乎有一个链表,而您只是复制头部和尾部指针。因此,当你制作一个副本,一个被销毁时,它也会破坏另一个副本。

我假设你的默认构造函数和/或你的add函数做了一些动态的节点分配。然后,您的复制构造函数和赋值运算符也需要动态分配节点,这些节点完全独立于正在复制的对象的节点。如果您可以使用C ++ 11,则还应考虑实现move constructor和移动赋值运算符。

一旦这些功能都正确,您的操作员+应该看起来像这样:

Occurance Occurance::operator +(const Occurance& occ) const {
    Occurance result; // no dynamic allocation

    // operate on result

    return result;
}