C ++ Copy Constructor奇怪的行为

时间:2011-08-12 19:34:34

标签: c++ copy-constructor

给出以下代码:

class monomial {
public:
    mp_real coe;
    int exp;        
    monomial *next; 
};

class polynomial  
{  
private:
    monomial *start;
public:
    polynomial();
    ~polynomial();
    void destroy_poly(monomial *);
    polynomial & operator=(const polynomial &);
    polynomial(const polynomial&);
    monomial * get_start();
};  
polynomial::polynomial() {
    start = NULL;
}
polynomial::~polynomial() {
    if (start != NULL) {
        destroy_poly(start);
    }
    start = NULL;
}
void
polynomial::destroy_poly(monomial * m) {
    monomial * cm = m;
    if (cm->next != NULL) {
        destroy_poly(cm->next);
    }
    delete m;
}
polynomial::polynomial(const polynomial& p) {
    if (p.start != NULL) {
        start = new monomial();
        start->coe = p.start->coe;
        start->exp = p.start->exp;

        monomial * tmpPtr = p.start;
        monomial * lastPtr = start;

        while (tmpPtr->next != NULL) {
            monomial * newMon = new monomial();
            newMon->coe = tmpPtr->next->coe;
            newMon->exp = tmpPtr->next->exp;

            lastPtr->next = newMon;
            lastPtr = lastPtr->next;
            tmpPtr = tmpPtr->next;
        }
    }
}
polynomial & polynomial::operator=(const polynomial &p) {
    if (p.start != NULL) {
        start = new monomial();
        start->coe = p.start->coe;
        start->exp = p.start->exp;

        monomial * tmpPtr = p.start;
        monomial * lastPtr = start;

        while (tmpPtr->next != NULL) {
            monomial * newMon = new monomial();
            newMon->coe = tmpPtr->next->coe;
            newMon->exp = tmpPtr->next->exp;

            lastPtr->next = newMon;
            lastPtr = lastPtr->next;
            tmpPtr = tmpPtr->next;
        }
    }
    return *this;
}

然后在main.cpp中:

main() {
    polynomial poly;
    // code that initializes / sets values for 
    // various monomials pointed to by poly.start.

    map<set<unsigned int>, polynomial> hash;
    set<unsigned int> tmpSet;

    tmpSet.insert(0);

    hash[tmpSet] = poly;
}

我可以在复制构造函数的第一行设置断点,在我跳过hash [tmpSet] = poly line之后,复制构造函数中的p.start为NULL。然后,它第二次被调用,此时p.start在其中设置了奇怪的值。

有什么想法发生了什么?

谢谢, 埃里希

编辑1:考虑将赋值运算符添加到多项式类中修复它,但它没有。还有同样的问题。

5 个答案:

答案 0 :(得分:4)

您违反了 Rule of Three
由于您超载复制构造函数,您为您的类重载复制赋值运算符析构函数

上述声明是参考一般情况,在您的代码示例中,您可以将 替换为必须

答案 1 :(得分:2)

两个问题。

1)您没有无参数构造函数,因此编译器会在其认为合适的情况下填充初始值。 p.start最初为NULL的事实是

2)当您的复制构造函数传递polynomial p.start == NULL时,您不会初始化类中的任何变量,因此下一个副本可以具有编译器分配的任何初始值(请参阅问题#1)。

要修复,你应该添加一个no-arg构造函数,将多项式初始化为一个理智的状态。然后复制构造函数,如果传递了这样的多项式,应该将自己初始化为一个理智的状态。

答案 2 :(得分:0)

您应该添加一个默认构造函数,初始化start为NULL。

答案 3 :(得分:0)

正如Als指出的那样,你违反了三法则。 好吧,当你把一些东西放在容器中时,你的指针会发生什么。

monomial *start;
monomial *next;

想一想。

答案 4 :(得分:0)

如果p.start == NULL,您的复制构造函数会将start set设置为某个随机值。这可能是问题的原因,具体取决于程序中的其他代码。 此外,您没有赋值运算符,因此编译器正在为您执行浅拷贝。您必须添加另一个函数polynomial &operator=(const polynomial& b)