我必须为两个动态容器重载'+'运算符。
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();
};
答案 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;
}