class 中的赋值运算符,_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
assignment operator in class, _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
我目前有一个如下所示的赋值运算符:
CellPhoneHandler CellPhoneHandler:: operator=(const CellPhoneHandler &original){
if (this->nrOfCellphones > 0)
for (int i = 0; i < this->nrOfCellphones; i++) {
delete this->cellphone[i];
}
delete[] cellphone;
this->nrOfCellphones = original.nrOfCellphones;
this->cellphone = new CellPhone*[this->nrOfCellphones];
for (int i = 0; i<this->nrOfCellphones; i++)
{
cellphone[i] = original.cellphone[i];
}
return *this;
}
然后在程序开始时,我打算测试它是否正常工作:
CellPhoneHandler assignme;
assignme.addPhone("assignment phone", 500, 1000);
assignme.addPhone("assignment phone 2", 500, 1000);
copyme = assignme;
但是,当我退出程序时,出现未处理的异常,该异常指向 dbgdel.cpp 中的第 52 行:
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
有什么想法吗?问题似乎只出在这个函数中,因为当我将测试从程序中注释掉时它就起作用了。
我的手机 class 看起来像这样:
class CellPhone
{
private:
string model;
int stock;
double price;
public:
CellPhone(string model="", int stock=0, double price=0); // constructor
string getModel()const;
int getStock()const;
double getPrice()const;
void setModel(string model);
void setStock(int stock);
void setPrice(double price);
string toString() const;
~CellPhone(); //destructor
};
改了原来的变量名,还是报错
class CellPhoneHandler
{
private:
CellPhone **cellphone;
int nrOfCellphones;
public:
CellPhoneHandler();
CellPhoneHandler(const CellPhoneHandler &original);
CellPhoneHandler operator=(const CellPhoneHandler &original);
void addPhone(string model, int price, int stock);
~CellPhoneHandler();
string showByStock(int stock) const;
void removeModel(string model);
void changePriceProcent(double procent, int price);
void showAll(string array[], int nrOfCellphones) const;
void saveToFile(string fileName) const;
void readFromFile(string fileName);
int getNrOfPhones()const;
};
更新:将我的 operator= 更改为此,简化代码:
CellPhoneHandler CellPhoneHandler:: operator=(const CellPhoneHandler &original){
CellPhoneHandler tmp(original);
swap(this->cellphone, tmp.cellphone);
swap(this-> nrOfCellphones, tmp.nrOfCellphones);
return *this;
}
该程序现在可以运行了,但是,这是深度复制吗?我的老师告诉我我上次的作业没有那样做。
您的赋值运算符应该返回 CellPhoneHandler&
,而不是 CellPhoneHandler
对象。通过返回一个对象,您正在(不必要地)调用复制构造函数。
此外,您的赋值运算符无法检查自赋值(将 CellPhoneHandler
对象赋给自身)。自赋值将删除对象的数据,然后尝试从已删除的内存区域进行复制。
如果对 new[]
的调用抛出异常,赋值运算符也会失败。在发出对 new[]
的调用之前,您正在更改对象的内部结构,因此如果出现问题并且 new[]
抛出异常,则会破坏对象。
但是,您可以利用复制构造函数和析构函数使用 copy / swap idiom:
来实现赋值运算符,而不是编写所有这些代码来实现赋值运算符
#include <algorithm>
//...
CellPhoneHandler& CellPhoneHandler:: operator=(const CellPhoneHandler &original)
{
CellPhoneHandler temp(original);
std::swap(temp.nrOfCellphones, nrOfCellphones);
std::swap(temp.cellphone, cellphone);
return *this;
}
这现在通过创建一个临时对象来使用复制构造函数,并且只是用当前对象的内部交换临时对象的内部。然后临时对象消失。
这是异常安全的(因为如果在构造 temp
时出现任何问题,原始对象不会发生任何事情),并且无需检查自赋值(您可以这样做以进行可能的优化,但是无需实际执行此检查,这与您最初尝试的赋值运算符不同。
我目前有一个如下所示的赋值运算符:
CellPhoneHandler CellPhoneHandler:: operator=(const CellPhoneHandler &original){
if (this->nrOfCellphones > 0)
for (int i = 0; i < this->nrOfCellphones; i++) {
delete this->cellphone[i];
}
delete[] cellphone;
this->nrOfCellphones = original.nrOfCellphones;
this->cellphone = new CellPhone*[this->nrOfCellphones];
for (int i = 0; i<this->nrOfCellphones; i++)
{
cellphone[i] = original.cellphone[i];
}
return *this;
}
然后在程序开始时,我打算测试它是否正常工作:
CellPhoneHandler assignme;
assignme.addPhone("assignment phone", 500, 1000);
assignme.addPhone("assignment phone 2", 500, 1000);
copyme = assignme;
但是,当我退出程序时,出现未处理的异常,该异常指向 dbgdel.cpp 中的第 52 行:
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
有什么想法吗?问题似乎只出在这个函数中,因为当我将测试从程序中注释掉时它就起作用了。
我的手机 class 看起来像这样:
class CellPhone
{
private:
string model;
int stock;
double price;
public:
CellPhone(string model="", int stock=0, double price=0); // constructor
string getModel()const;
int getStock()const;
double getPrice()const;
void setModel(string model);
void setStock(int stock);
void setPrice(double price);
string toString() const;
~CellPhone(); //destructor
};
改了原来的变量名,还是报错
class CellPhoneHandler
{
private:
CellPhone **cellphone;
int nrOfCellphones;
public:
CellPhoneHandler();
CellPhoneHandler(const CellPhoneHandler &original);
CellPhoneHandler operator=(const CellPhoneHandler &original);
void addPhone(string model, int price, int stock);
~CellPhoneHandler();
string showByStock(int stock) const;
void removeModel(string model);
void changePriceProcent(double procent, int price);
void showAll(string array[], int nrOfCellphones) const;
void saveToFile(string fileName) const;
void readFromFile(string fileName);
int getNrOfPhones()const;
};
更新:将我的 operator= 更改为此,简化代码:
CellPhoneHandler CellPhoneHandler:: operator=(const CellPhoneHandler &original){
CellPhoneHandler tmp(original);
swap(this->cellphone, tmp.cellphone);
swap(this-> nrOfCellphones, tmp.nrOfCellphones);
return *this;
}
该程序现在可以运行了,但是,这是深度复制吗?我的老师告诉我我上次的作业没有那样做。
您的赋值运算符应该返回 CellPhoneHandler&
,而不是 CellPhoneHandler
对象。通过返回一个对象,您正在(不必要地)调用复制构造函数。
此外,您的赋值运算符无法检查自赋值(将 CellPhoneHandler
对象赋给自身)。自赋值将删除对象的数据,然后尝试从已删除的内存区域进行复制。
如果对 new[]
的调用抛出异常,赋值运算符也会失败。在发出对 new[]
的调用之前,您正在更改对象的内部结构,因此如果出现问题并且 new[]
抛出异常,则会破坏对象。
但是,您可以利用复制构造函数和析构函数使用 copy / swap idiom:
来实现赋值运算符,而不是编写所有这些代码来实现赋值运算符#include <algorithm>
//...
CellPhoneHandler& CellPhoneHandler:: operator=(const CellPhoneHandler &original)
{
CellPhoneHandler temp(original);
std::swap(temp.nrOfCellphones, nrOfCellphones);
std::swap(temp.cellphone, cellphone);
return *this;
}
这现在通过创建一个临时对象来使用复制构造函数,并且只是用当前对象的内部交换临时对象的内部。然后临时对象消失。
这是异常安全的(因为如果在构造 temp
时出现任何问题,原始对象不会发生任何事情),并且无需检查自赋值(您可以这样做以进行可能的优化,但是无需实际执行此检查,这与您最初尝试的赋值运算符不同。