为什么我的重载运算符+在向自身添加变量时会在返回时使"this"未初始化?

Why would my overloaded operator+ make 'this' uninitialized on return when adding a variable to itself?

本文关键字:返回 this 初始化 添加 运算符 重载 我的 为什么 变量      更新时间:2023-10-16

我在代码中发现了一个错误,其中驱动程序中的行

t2 = t2 + t;

导致"this"在返回重载运算符+期间变得未初始化。使用调试工具,我的代码似乎在返回调用之前执行得很好,然后当我进入 return 时,它会将我带到我的复制构造函数,其中"this"指向与传递给它的 p 参数相同的头节点。但是一旦我将复制构造函数标头单步进入正文,"this"突然改变了它的内存位置并指向0xcccccccc,告诉我它没有初始化,这会导致我的构造函数出现问题,因为这不是空值。

我希望有人能让我了解到底发生了什么,以及如何解决它。显然,我可以使用我的运算符+=,因为它工作得很好,但理论上你应该能够进行这种调用而不会出错。

编辑:在收到指出我不知道做得更好的明显错误的注释后,我编辑了我的代码以包含帮助程序副本和清除方法,以在我的复制构造函数,析构函数和赋值运算符中使用。

更新的实现:

#include "polynomial.h" //header
#include <stdlib.h>
// Default Constructor:the default is a 0-degree polynomial with 0.0 coefficient
Polynomial::Polynomial() {
size = 0;
head = new Term;
head->coeff = 0;
head->power = 0;
head->next = head;
head->prev = head;
}
// Copy Constructor
Polynomial::Polynomial(const Polynomial &p) {
copy(p);
}
// Destructor
Polynomial::~Polynomial() {
clear();
}
// degree: returns degree of polynomial
// Pre: none (an empty polynomial will return as a 0-degree)
// Post: the largest degree in the polynomial is returned as an int
int Polynomial::degree() const {
return head->next->power;
}
// coefficient: returns the coefficient of the x^power Term
// Pre: none
// Post: the coefficient, if an x^power Term exists, is return. If 
//      an x^power Term doesn't exist, 0 is returned
double Polynomial::coefficient(const int power) const {
Term *thisPointer = head->next;
while (thisPointer->power != power && thisPointer != head) thisPointer = thisPointer->next;
if (thisPointer == head) return 0;
return thisPointer->coeff;
}
// changeCoefficient: replaces the coefficient of the x^power term
// Pre: none
// Post: if an x^power Term exists, its coefficient will be changed to 
//      newCoefficient. If not, an x^power Term with that coefficient will be inserted
bool Polynomial::changeCoefficient(const double newCoefficient, const int power) {
if (head == NULL) *this = Polynomial();
Term *thisPointer = head->next;
// either finds value to be changed or stops before head, indicating need for insertion
while (thisPointer->power != power && thisPointer->next != head)
thisPointer = thisPointer->next;
// finds proper location for insertion if cycled through list
if (thisPointer->next == head) {
thisPointer = head;
while (thisPointer->next->power > power) thisPointer = thisPointer->next;
insert(thisPointer->next, newCoefficient, power);
}
else if (newCoefficient == 0) {
remove(thisPointer);
} else thisPointer->coeff = newCoefficient;
return true;
}
// insert: inserts an x^power Term with coefficient newCoefficient into the
//      polynomial, directly just before the pos Term
// Pre: the function is passed a nonzero newCoefficient and a pos Term that
//      exists in the polynomial
// Post: returns true if new Term was successfully inserted, returns false if
//      pre conditions are not met
bool Polynomial::insert(Term* pos, const double newCoefficient, const int power) {
if (newCoefficient == 0) return false;
Term *thisPointer = head;
while (thisPointer->next != pos && thisPointer->next != head)
thisPointer = thisPointer->next;
// returns false if pos Term is not found
if (size > 0 && thisPointer->next == head && pos != head) return false;
// creates new term using parameters
Term *newTerm = new Term;
newTerm->power = power;
newTerm->coeff = newCoefficient;
// redirects pointers of adjacent Terms to include newTerm in polynomial
newTerm->next = thisPointer->next;
newTerm->prev = thisPointer;
thisPointer->next->prev = newTerm;
thisPointer->next = newTerm;
size++;
return true;
}
// remove: removes pos Term from polynomial
// Pre: pos Term exists in polynomial
// Post: returns true if pos Term was successfuly removed, if not returns false
bool Polynomial::remove(Term* pos) {
Term *thisPointer = head;
// finds term before one to be deleted
while (thisPointer->next != pos && thisPointer->next != head) thisPointer = thisPointer->next;
//returns false if pos term is not found
if (thisPointer->next == head) return false;
// redirects pointers of adjacent Terms around pos, removes pos
thisPointer->next = thisPointer->next->next;
thisPointer->next->prev->prev = NULL;
thisPointer->next->prev->next = NULL;
delete thisPointer->next->prev;
thisPointer->next->prev = thisPointer;
size--;
return true;
}
// clear: removes all terms of polynomial from memory
// Pre:
// Post: 
void Polynomial::clear() {
if (head != NULL) {
while (head->next != head) {
Term *thisPointer = head;
head = head->next;
remove(thisPointer);
}
head->next = head;
head->prev = head;
head->coeff = 0;
}
}
// copy:
// Pre:
// Post: 
void Polynomial::copy(const Polynomial &p) {
Term *pPointer = p.head;
if (pPointer == NULL) head = NULL;
else {
head = new Term;
head->coeff = 0;
head->power = 0;
head->next = head;
head->prev = head;
size = p.size;
//copy rest of polynomial
Term *thisPointer = head;
while (pPointer->next != p.head) {
pPointer = pPointer->next;
double coeff = pPointer->coeff;
int power = pPointer->power;
// create new Term with data from Term in p
Term *newTerm = new Term;
thisPointer->next = newTerm;
newTerm->prev = thisPointer;
newTerm->coeff = coeff;
newTerm->power = power;
thisPointer = thisPointer->next;
// checks for end of p to link head and last term
if (pPointer->next == p.head) {
head->prev = thisPointer;
thisPointer->next = head;
}
}
}
}
// Overloaded <<: prints Cn * x^n + Cn-1 * X^n-1 + ... C1 * X + C0
ostream& operator<<(ostream &output, const Polynomial& p) {
Polynomial::Term *thisPointer = p.head->next;
if (thisPointer != NULL) {
while (thisPointer != p.head) {
if (thisPointer->coeff < 0) output << "-";
else if (thisPointer->prev != p.head) output << " + ";
if (abs(thisPointer->coeff) != 1) output << abs(thisPointer->coeff);
if (abs(thisPointer->power) == 1) output << "x";
else if(thisPointer->power != 0) output << "x^" << thisPointer->power;
thisPointer = thisPointer->next;
}
}
return output;
}
// Overloaded operator+
Polynomial Polynomial::operator+(const Polynomial &in) const {
Polynomial out = *this;
out += in;
return out;
}
// Overloaded operator-
Polynomial Polynomial::operator-(const Polynomial &in) const {
Polynomial out = *this;
out -= in;
return out;
}
// Overloaded operator==
bool Polynomial::operator==(const Polynomial &in) const {
Term *thisPointer = head->next;
Term *inPointer = in.head->next;
while (thisPointer != head || inPointer != in.head) {
if (thisPointer->power != inPointer->power || 
thisPointer->coeff != inPointer->coeff) return false;
thisPointer = thisPointer->next;
inPointer = inPointer->next;
}
return true;
}
// Overloaded operator!=
bool Polynomial::operator!=(const Polynomial &in) const {
return !(*this == in);
}
// Overloaded operator=
Polynomial& Polynomial::operator=(const Polynomial &p) {
if (*this != p) {
clear();
copy(p);
}
return *this;
}
// Overloaded operator+=
Polynomial& Polynomial::operator+=(const Polynomial &in) {
Term *thisPointer = head;
Term *inPointer = in.head;
while (thisPointer->next != head || inPointer->next != in.head) {
int power = inPointer->next->power;
double coeff = inPointer->next->coeff;
// if t > p, insert t in p
if (power > thisPointer->next->power) {
insert(thisPointer->next, coeff, power);
thisPointer = thisPointer->next;
}
// if p power = t power, add 
else if (power == thisPointer->next->power)
thisPointer->next->coeff += coeff;
if (thisPointer->next->coeff == 0) remove(thisPointer->next);
// only advances t if p->next isn't larger than t->next
if (inPointer->next->power <= thisPointer->next->power)
thisPointer = thisPointer->next;
inPointer = inPointer->next;
}
return *this;
}
// Overloaded operator-=
Polynomial& Polynomial::operator-=(const Polynomial &in) {
Term *thisPointer = head;
Term *inPointer = in.head;
while (thisPointer->next != head || inPointer->next != in.head) {
int power = inPointer->next->power;
double coeff = inPointer->next->coeff;
// if t > p, insert t in p
if (power > thisPointer->next->power) {
insert(thisPointer->next, -coeff, power);
thisPointer = thisPointer->next;
}
// if p power = t power, subtract 
else if (power == thisPointer->next->power)
thisPointer->next->coeff -= coeff;
if (thisPointer->next->coeff == 0) remove(thisPointer->next);
// only advances t if p->next isn't larger than t->next
if (inPointer->next->power <= thisPointer->next->power)
thisPointer = thisPointer->next;
inPointer = inPointer->next;
}
return *this;
}

驱动程序文件:

#include <iostream>
using namespace std;
#include "polynomial.h"
int main() {
Polynomial t;
// adds new Terms using changeCoefficient
t.changeCoefficient(1, 1);
t.changeCoefficient(2, 2);
t.changeCoefficient(3, 3);
t.changeCoefficient(4, 5);
t.changeCoefficient(-5, 4);
cout << "t = " << t << endl;
// degree() demonstration
cout << "t's degree = " << t.degree() << endl;
// changing coefficients/deleting terms/adding constant value
t.changeCoefficient(1, 3);
t.changeCoefficient(9, 0);
t.changeCoefficient(0, 5);
cout << "t = " << t << endl;
cout << "t's degree = " << t.degree() << endl;
// copy constructor and operator= demonstration
Polynomial t2 = t + t;
// operator+ demonstration
t2 = t2 + t;
cout << "t2 = " << t2 << endl;
// operator!= demonstration
cout << "t2 does not equal t, right? " << boolalpha << (t2 != t) << endl;
// operator- demonstration
Polynomial t3 = t - t2;
cout << "t3 = " << t3 << endl;
// operator-= demonstration
t2 -= t;
cout << "t2 = " << t2 << endl;
// operator== demonstration
cout << "Does t2 equal t now? " << boolalpha << (t2 == t) << endl;
// operator+= demonstration, tests that subtraction was done properly, and
// t3 = empty polynomial
t3 += t;
cout << "t3 = " << t3 << endl;
}

旧的实现文件:

#include "polynomial.h" //header
#include <stdlib.h>
// Default Constructor:the default is a 0-degree polynomial with 0.0 coefficient
Polynomial::Polynomial() {
size = 0;
head = new Term;
head->coeff = 0;
head->power = 0;
head->next = head;
head->prev = head;
}
// Copy Constructor
Polynomial::Polynomial(const Polynomial &p) {
Term *pPointer = p.head;
if (pPointer == NULL) head = NULL;
else if (this != &p) {
if (head != NULL) this->~Polynomial();
head = new Term;
head->coeff = 0;
head->power = 0;
head->next = head;
head->prev = head;
size = p.size;
//copy rest of polynomial
Term *thisPointer = head;
while (pPointer->next != p.head) {
pPointer = pPointer->next;
double coeff = pPointer->coeff;
int power = pPointer->power;
// create new Term with data from Term in p
Term *newTerm = new Term;
thisPointer->next = newTerm;
newTerm->prev = thisPointer;
newTerm->coeff = coeff;
newTerm->power = power;
thisPointer = thisPointer->next;
// checks for end of p to link head and last term
if (pPointer->next == p.head) {
head->prev = thisPointer;
thisPointer->next = head;
}
}
}
}
// Destructor
Polynomial::~Polynomial() {
if (head != NULL) {
while (head->next != head) {
Term *thisPointer = head;
head = head->next;
remove(thisPointer);
}
head->next = head;
head->prev = head;
head->coeff = 0;
size = 0;
}
}
// degree: returns degree of polynomial
// Pre: none (an empty polynomial will return as a 0-degree)
// Post: the largest degree in the polynomial is returned as an int
int Polynomial::degree() const {
return head->next->power;
}
// coefficient: returns the coefficient of the x^power Term
// Pre: none
// Post: the coefficient, if an x^power Term exists, is return. If 
//      an x^power Term doesn't exist, 0 is returned
double Polynomial::coefficient(const int power) const {
Term *thisPointer = head->next;
while (thisPointer->power != power && thisPointer != head) thisPointer = thisPointer->next;
if (thisPointer == head) return 0;
return thisPointer->coeff;
}
// changeCoefficient: replaces the coefficient of the x^power term
// Pre: none
// Post: if an x^power Term exists, its coefficient will be changed to 
//      newCoefficient. If not, an x^power Term with that coefficient will be inserted
bool Polynomial::changeCoefficient(const double newCoefficient, const int power) {
if (head == NULL) *this = Polynomial();
Term *thisPointer = head->next;
// either finds value to be changed or stops before head, indicating need for insertion
while (thisPointer->power != power && thisPointer->next != head)
thisPointer = thisPointer->next;
// finds proper location for insertion if cycled through list
if (thisPointer->next == head) {
thisPointer = head;
while (thisPointer->next->power > power) thisPointer = thisPointer->next;
insert(thisPointer->next, newCoefficient, power);
}
else if (newCoefficient == 0) {
remove(thisPointer);
} else thisPointer->coeff = newCoefficient;
return true;
}
// insert: inserts an x^power Term with coefficient newCoefficient into the
//      polynomial, directly just before the pos Term
// Pre: the function is passed a nonzero newCoefficient and a pos Term that
//      exists in the polynomial
// Post: returns true if new Term was successfully inserted, returns false if
//      pre conditions are not met
bool Polynomial::insert(Term* pos, const double newCoefficient, const int power) {
if (newCoefficient == 0) return false;
Term *thisPointer = head;
while (thisPointer->next != pos && thisPointer->next != head)
thisPointer = thisPointer->next;
// returns false if pos Term is not found
if (size > 0 && thisPointer->next == head && pos != head) return false;
// creates new term using parameters
Term *newTerm = new Term;
newTerm->power = power;
newTerm->coeff = newCoefficient;
// redirects pointers of adjacent Terms to include newTerm in polynomial
newTerm->next = thisPointer->next;
newTerm->prev = thisPointer;
thisPointer->next->prev = newTerm;
thisPointer->next = newTerm;
size++;
return true;
}
// remove: removes pos Term from polynomial
// Pre: pos Term exists in polynomial
// Post: returns true if pos Term was successfuly removed, if not returns false
bool Polynomial::remove(Term* pos) {
Term *thisPointer = head;
// finds term before one to be deleted
while (thisPointer->next != pos && thisPointer->next != head) thisPointer = thisPointer->next;
//returns false if pos term is not found
if (thisPointer->next == head) return false;
// redirects pointers of adjacent Terms around pos, removes pos
thisPointer->next = thisPointer->next->next;
thisPointer->next->prev->prev = NULL;
thisPointer->next->prev->next = NULL;
delete thisPointer->next->prev;
thisPointer->next->prev = thisPointer;
size--;
return true;
}
// Overloaded <<: prints Cn * x^n + Cn-1 * X^n-1 + ... C1 * X + C0
ostream& operator<<(ostream &output, const Polynomial& p) {
Polynomial::Term *thisPointer = p.head->next;
if (thisPointer != NULL) {
while (thisPointer != p.head) {
if (thisPointer->coeff < 0) output << "-";
else if (thisPointer->prev != p.head) output << " + ";
if (abs(thisPointer->coeff) != 1) output << abs(thisPointer->coeff);
if (abs(thisPointer->power) == 1) output << "x";
else if(thisPointer->power != 0) output << "x^" << thisPointer->power;
thisPointer = thisPointer->next;
}
}
return output;
}
// Overloaded operator+
Polynomial Polynomial::operator+(const Polynomial &in) const {
Polynomial out = *this;
out += in;
return out;
}
// Overloaded operator-
Polynomial Polynomial::operator-(const Polynomial &in) const {
Polynomial out = *this;
out -= in;
return out;
}
// Overloaded operator==
bool Polynomial::operator==(const Polynomial &in) const {
Term *thisPointer = head->next;
Term *inPointer = in.head->next;
while (thisPointer != head || inPointer != in.head) {
if (thisPointer->power != inPointer->power || 
thisPointer->coeff != inPointer->coeff) return false;
thisPointer = thisPointer->next;
inPointer = inPointer->next;
}
return true;
}
// Overloaded operator!=
bool Polynomial::operator!=(const Polynomial &in) const {
return !(*this == in);
}
// Overloaded operator=
Polynomial& Polynomial::operator=(const Polynomial &p) {
if (*this != p) {
this->~Polynomial();
*this = p;
}
return *this;
}
// Overloaded operator+=
Polynomial& Polynomial::operator+=(const Polynomial &in) {
Term *thisPointer = head;
Term *inPointer = in.head;
while (thisPointer->next != head || inPointer->next != in.head) {
int power = inPointer->next->power;
double coeff = inPointer->next->coeff;
// if t > p, insert t in p
if (power > thisPointer->next->power) {
insert(thisPointer->next, coeff, power);
thisPointer = thisPointer->next;
}
// if p power = t power, add 
else if (power == thisPointer->next->power)
thisPointer->next->coeff += coeff;
if (thisPointer->next->coeff == 0) remove(thisPointer->next);
// only advances t if p->next isn't larger than t->next
if (inPointer->next->power <= thisPointer->next->power)
thisPointer = thisPointer->next;
inPointer = inPointer->next;
}
return *this;
}
// Overloaded operator-=
Polynomial& Polynomial::operator-=(const Polynomial &in) {
Term *thisPointer = head;
Term *inPointer = in.head;
while (thisPointer->next != head || inPointer->next != in.head) {
int power = inPointer->next->power;
double coeff = inPointer->next->coeff;
// if t > p, insert t in p
if (power > thisPointer->next->power) {
insert(thisPointer->next, -coeff, power);
thisPointer = thisPointer->next;
}
// if p power = t power, subtract 
else if (power == thisPointer->next->power)
thisPointer->next->coeff -= coeff;
if (thisPointer->next->coeff == 0) remove(thisPointer->next);
// only advances t if p->next isn't larger than t->next
if (inPointer->next->power <= thisPointer->next->power)
thisPointer = thisPointer->next;
inPointer = inPointer->next;
}
return *this;
}

将赋值运算符函数实现为:

Polynomial& Polynomial::operator=(const Polynomial &p) {
if (*this != p) {
this->~Polynomial();
*this = p;
}
return *this;
}

如果if语句中的条件为true,这将导致无限递归,您的用例就是这种情况。

这也是错误的,并导致未定义的行为。

行后

this->~Polynomial();

对象已死。任何取消引用this的尝试都是未定义行为的原因。

您可能希望使用复制和交换习惯用法来实现复制赋值运算符。