c++复制构造函数的奇怪行为

C++ Copy Constructor Strange Behavior

本文关键字:复制 构造函数 c++      更新时间:2023-10-16

给定以下代码:

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;
}

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

知道发生了什么事吗?

谢谢,Erich

编辑1:本以为在多项式类中添加赋值操作符可以解决这个问题,但事实并非如此。还是有同样的问题

你违反了三原则:
由于重载了复制构造函数,因此应该重载复制赋值操作符析构函数

在您的代码示例中,可以将should替换为must

两个问题

1)你没有一个无参数的构造函数,所以编译器在它认为合适的情况下归档初始值。p.start初始值为NULL的事实是

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

要解决这个问题,您应该添加一个无参数构造函数,将多项式初始化为相同的状态。然后复制构造函数,如果传递了这样一个多项式,应该将自己初始化为一个相同的状态。

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

正如al指出的那样,你违反了三原则。看,当你把东西放进容器时指针会发生什么变化

monomial *start;
monomial *next;

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