我应该删除运算符赋值函数中的原点指针吗?
Should I delete origin pointer in operator assignment function?
我编写了以下演示代码来学习复制构造函数和赋值运算符。但是有一点混乱。我被告知删除赋值运算符中的指针并将新地址分配给 data
。但是我只能让我的代码工作删除该行。我以 this 页面作为参考,但它只显示了 int 的示例,而没有显示 int*
。我该如何解决这个问题?
#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>
using namespace boost;
class ClassOne
{
public:
ClassOne():data(NULL) {}
ClassOne(int data_param):data(NULL)
{
init(data_param);
std::cout << "construct" << std::endl;
}
virtual ~ClassOne()
{
if (data) {
delete data;
}
data = NULL;
}
ClassOne(const ClassOne& rhs){
std::cout<< "copy " <<std::endl;
data = NULL;
init(*rhs.data);
}
ClassOne& operator = (const ClassOne& rhs){
std::cout<< "assign " <<std::endl;
int* p_old = rhs.data;
data = new int(*p_old);
//delete p_old; // I have to delete this line to make my code work
return *this;
}
void init(int data_param)
{
if (data) {
delete data;
}
data = new int(data_param);
}
private:
int* data;
};
int main(int argc, const char * argv[]) {
ClassOne c1(10);
ClassOne c2(c1); // call copy constructor
ClassOne c3;
c3 = c1; // call assignment function
return 0;
}
您正试图删除其他对象的 data
成员,而您打算删除自己 (this
) 对象的当前 data
成员。你可能想要的是:
ClassOne& operator = (const ClassOne& rhs){
std::cout<< "assign " <<std::endl;
delete data; // delete your own old data
data = new int(*rhs.data); // clone the rhs's data
return *this;
}
你的代码失败是因为你重复删除了一些东西:你删除了复制赋值和析构函数中的指针。删除指针不会使其为空,这就是它在析构函数中传递 if 的原因。 (顺便说一句,你不需要在删除之前检查指针是否为空,delete
无论如何都会检查)
我建议复制赋值不要改变rhs
变量,因为删除data
指针很容易导致内存访问。我宁愿实现一个移动构造函数和赋值来使这种行为明确。我会删除复制构造函数和赋值并添加这些函数:
ClassOne(const ClassOne&) = delete;
ClassOne& operator=(const ClassOne&) = delete;
ClassOne(ClassOne&& rhs) {
std::swap(data, rhs.data);
}
ClassOne& operator=(ClassOne&& rhs) {
std::swap(data, rhs.data);
}
这将需要 std::move
被调用。
或者,您可以实现一个 non-stealing 复制构造函数。这将需要您深复制数据指针(复制内容而不是指针)
ClassOne(const ClassOne& rhs) {
if (!data) {
data = new int;
}
*data = *(rhs.data);
}
ClassOne& operator=(const ClassOne& rhs) {
if (!data) {
data = new int;
}
*data = *(rhs.data);
}
我编写了以下演示代码来学习复制构造函数和赋值运算符。但是有一点混乱。我被告知删除赋值运算符中的指针并将新地址分配给 data
。但是我只能让我的代码工作删除该行。我以 this 页面作为参考,但它只显示了 int 的示例,而没有显示 int*
。我该如何解决这个问题?
#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>
using namespace boost;
class ClassOne
{
public:
ClassOne():data(NULL) {}
ClassOne(int data_param):data(NULL)
{
init(data_param);
std::cout << "construct" << std::endl;
}
virtual ~ClassOne()
{
if (data) {
delete data;
}
data = NULL;
}
ClassOne(const ClassOne& rhs){
std::cout<< "copy " <<std::endl;
data = NULL;
init(*rhs.data);
}
ClassOne& operator = (const ClassOne& rhs){
std::cout<< "assign " <<std::endl;
int* p_old = rhs.data;
data = new int(*p_old);
//delete p_old; // I have to delete this line to make my code work
return *this;
}
void init(int data_param)
{
if (data) {
delete data;
}
data = new int(data_param);
}
private:
int* data;
};
int main(int argc, const char * argv[]) {
ClassOne c1(10);
ClassOne c2(c1); // call copy constructor
ClassOne c3;
c3 = c1; // call assignment function
return 0;
}
您正试图删除其他对象的 data
成员,而您打算删除自己 (this
) 对象的当前 data
成员。你可能想要的是:
ClassOne& operator = (const ClassOne& rhs){
std::cout<< "assign " <<std::endl;
delete data; // delete your own old data
data = new int(*rhs.data); // clone the rhs's data
return *this;
}
你的代码失败是因为你重复删除了一些东西:你删除了复制赋值和析构函数中的指针。删除指针不会使其为空,这就是它在析构函数中传递 if 的原因。 (顺便说一句,你不需要在删除之前检查指针是否为空,delete
无论如何都会检查)
我建议复制赋值不要改变rhs
变量,因为删除data
指针很容易导致内存访问。我宁愿实现一个移动构造函数和赋值来使这种行为明确。我会删除复制构造函数和赋值并添加这些函数:
ClassOne(const ClassOne&) = delete;
ClassOne& operator=(const ClassOne&) = delete;
ClassOne(ClassOne&& rhs) {
std::swap(data, rhs.data);
}
ClassOne& operator=(ClassOne&& rhs) {
std::swap(data, rhs.data);
}
这将需要 std::move
被调用。
或者,您可以实现一个 non-stealing 复制构造函数。这将需要您深复制数据指针(复制内容而不是指针)
ClassOne(const ClassOne& rhs) {
if (!data) {
data = new int;
}
*data = *(rhs.data);
}
ClassOne& operator=(const ClassOne& rhs) {
if (!data) {
data = new int;
}
*data = *(rhs.data);
}