运算符重载-C++ 操作符重载的内存释放问题

问题描述

C++ 操作符重载的内存释放问题

=操作符重载,给复构造函数进行赋值时的代码如下:

MyString & MyString::operator =(const MyString &str)
{
if(this == &str)
return *this;

    delete []m_pData;    //**???????????????????????????? **
    m_pData = NULL;

    m_pData = new char(strlen(str.m_pData) + 1);
    strcpy (m_pData, str.m_pData);

    return *this;

}

class MyString
{
public:
....
private:
char *m_pData;
}

在函数中为什么还要是对原有的内存进行释放,即delete []m_pData,直接赋值 m_pData = str.m_pData, 这样不行吗?

请大神指点。

解决方案

有两个问题:
1. 如果不delete,那么m_pData重新赋值后,原先指向的的内存不能被访问,也没有被回收给程序继续使用,相当于你的内存就减小了一块,也就是内存泄漏。
2. 不管是否delete,执行m_pData = str.m_pData都是错误的。因为这样,两个指针指向的是同一片地址,例如你执行str1 = str2,如果按你的方式来实现,那么以后修改str2中的字符串时,由于str1中的m_pData也指向同一片区域,因此str1中的字符串也会被修改。一般来说,这不是我们希望看到的结果。
类似于这样:

int a = 1, b = 2;
a = b;
b = 3;

那么我们希望此时a的值等于2,而不是3。如果执行了b = 3之后,a的值也变成了3,那自然是不符合预期的。

解决方案二:

赋值后,就指向了新的对象,那原来的对象中分配的空间就造成了了内存泄露,所以先释放

解决方案三:

原有的内存空间与新赋值的内存空间长度有可能不一致。如果新赋值的内存空间长度大于原有的内存空间长度,需要重新开辟空间存储。所以需要现删除原有的内存空间,然后重新分配内存空间。否则有可能造成内存泄露。

解决方案四:

#if 1
class MyString
{
public:
MyString(){}
MyString(char str)
{
if (NULL == str)
{
m_pData = new char[1];
m_pData[0] = '';
}
else
{
m_pData = new char[strlen(str) + 1];
strcpy_s(m_pData, strlen(m_pData), str);
}
}
MyString & operator =(const MyString &str);
char
Print()
{
return m_pData;
}

~MyString()
{
    delete[]m_pData;
    m_pData = NULL;
}

private:
char *m_pData;
};

MyString & MyString::operator =(const MyString &str)
{
if (this == &str)
return this;
//delete[]m_pData; //
*???????????????????????????? **
//m_pData = NULL;

//m_pData = new char(strlen(str.m_pData) + 1);
//strcpy_s(m_pData, strlen(m_pData), str.m_pData);
m_pData = str.m_pData;
return *this;

}

int main()
{
MyString str1 = "asd";
MyString str2;
str2 = str1;
cout << str2.Print() << endl;
return 0;
}
#endif


其一,浅拷贝只是拷贝了指针,使得两个指针指向同一个地址,这样在对象块结束,调用函数析构的时,会造成同一份资源析构2次,即delete同一块内存2次,造成程序崩溃。
其二,浅拷贝使得obj.m_data和obj1.m_data指向同一块内存,任何一方的变动都会影响到另一方。
其三,在释放内存的时候,会造成obj1.m_data原有的内存没有被释放(这句话,刚开始我不太理解,如果没有走自定义的拷贝构造函数,申请内存空间,A obj1(obj);也不走默认构造函数,走的是默认的拷贝构造函数,何来分配空间直说,更不会造成obj1.m_data原有的内存没有被释放,这里刚开始我一直有疑问),造成内存泄露。
事实是这样的,当delete obj.m_data, obj.m_data内存被释放后,由于之前obj.m_data和obj1.m_data指向的是同一个内存空间,obj1.m_data所指的空间不能在被利用了,delete obj1.m_data也不会成功,一致已经无法操作该空间,所以导致内存泄露。

时间: 2024-10-02 18:39:16

运算符重载-C++ 操作符重载的内存释放问题的相关文章

c++ 操作符重载-关于操作符重载的问题

问题描述 关于操作符重载的问题 C++中如果想要对某个类设计一个友元的操作符重载,比如string类型支持string1+string2. 如果返回一个引用的话,编译器会报错.因为返回的类是局部变量,无法引用. 比如: //此函数为List类的友元函数. //template friend List& operator+(List& L1,List& L2); template List& operator+(List& L1,List& L2) { Lis

C++中的操作符重载详细解析_C 语言

一.什么是操作符重载操作符重载可以分为两部分:"操作符"和"重载".说到重载想必都不陌生了吧,这是一种编译时多态,重载实际上可以分为函数重载和操作符重载.运算符重载和函数重载的不同之处在于操作符重载重载的一定是操作符.我们不妨先直观的看一下所谓的操作符重载: 复制代码 代码如下: #include <iostream> using namespace std; int main(){    int a = 2 , b = 3;    float c =

php重载数组操作符

在php中提供了许多接口用于实现一些很特定的功能,比如你想把一个对象当作array使用时,只需要实现ArrayAccess接口,当你想要foreach中能够使用一个对象时,只需要实现Iterator接口,下面给一个例子出来 class BtstoreRoot { /** * 根结点 * @var BtstoreElement */ static $root; } class BtstoreElement implements ArrayAccess, Iterator { /** * 当前所代表

【C/C++学院】(8)全局函数和类成员函数转化/友元/操作符重载

1.全局函数和类成员函数转化     全局函数和成员函数的相互转化:只需要修改一个指向本类的this指针: #include <iostream> using namespace std; class Test { public: Test(int a, int b) { this->a = a; this->b = b; } //成员函数 Test &Gadd2(Test &t2) { this->a = this->a + t2.a; this-&g

C#中奇妙的操作符重载

C#中奇妙的操作符重载 细心的朋友可能发现,C#虽然可以重载操作符,但和C++比较起来,却有很大的不同.定义的时候重载操作符方法必须是static,而且至少有一个参数(一目和二目分别是一个和两个),C#和C++比起来,最重要的特征是:<.>:==.!=:true.false必须成对出现,即重载了"<"就必须重载">",重载了"=="就必须重载"!=",重载了"true"就必须重载&q

C++中复制构造函数和重载赋值操作符总结_C 语言

前言 这篇文章将对C++中复制构造函数和重载赋值操作符进行总结,包括以下内容: 1.复制构造函数和重载赋值操作符的定义: 2.复制构造函数和重载赋值操作符的调用时机: 3.复制构造函数和重载赋值操作符的实现要点: 4.复制构造函数的一些细节. 复制构造函数和重载赋值操作符的定义 我们都知道,在C++中建立一个类,这个类中肯定会包括构造函数.析构函数.复制构造函数和重载赋值操作:即使在你没有明确定义的情况下,编译器也会给你生成这样的四个函数.例如以下类: 复制代码 代码如下: class CTes

操作符重载

1.重载函数作为成员函数和友元函数的区别     成员函数,其中一个操作数应为类本身,调用时也该类对象应在左边如:c1 + 3;友元函数可将该类放到任意位置. 2.重载++,--;在自增(自减)运算符重载函数中,增加一个int型形参,就是后置自增(自减)运算符. 3.重载流插入运算符和流提取运算符istream&operator>>(istream&, 自定义类&)  ostream&operator<<(ostream&, 自定义类&

iostream-errorC2679操作符重载

问题描述 errorC2679操作符重载 RT自己写了一个TIME类和SMSDATA类 "Time.h"声明如下 #ifndef _TIME_H #define _TIME_H #include using namespace std; class TIME { private: int hour; int min; int sec; public: friend ofstream& operator<< (ofstream& out, const TIME

C#锐利体验之第八讲 索引器与操作符重载

索引 索引器 索引器(Indexer)是C#引入的一个新型的类成员,它使得对象可以像数组那样被方便,直观的引用.索引器非常类似于我们前面讲到的属性,但索引器可以有参数列表,且只能作用在实例对象上,而不能在类上直接作用.下面是典型的索引器的设计,我们在这里忽略了具体的实现. class MyClass{    public object this [int index]    {        get        {            // 取数据        }        set