浅拷贝:类的所有对象的成员变量指针指向同一块空间(成员变量是开辟在堆区的),类默认的拷贝构造函数和赋值运算符重载都采用浅拷贝,如果不加以处理,当析构函数对空间进行释放时,就会出现堆区空间二次释放的问题。但是浅拷贝也可以起到节省内存空间的作用,这里就需要利用静态的成员变量来进行对象计数,析构函数中 对计数进行判断,如果只剩下一个对象再进行真正的析构操作。
深拷贝:对于拷贝构造和赋值运算符重载重新实现,赋值时每次都要开辟新空间。注意赋值运算符重载中,需要进行旧空间释放(不然会造成内存泄漏)和是否是自身赋值的判断。
所有对象都只是访问数据而不修改,浅拷贝是可以的,但是当有对象要进行数据修改时就应该按深拷贝来实现。深拷贝和浅拷贝(对象计数)的实现:这种所有的对象都进行统一引用计数的方式是错误的,比如s3应当和s1、s2没有关联,而且这里的成员变量一改俱改。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vld.h>
using namespace std;
class String
{
friend ostream& operator<<(ostream& cout, const String& s);
public:
String(const char* str="")
{
this->m_data = new char[strlen(str) + 1];
strcpy(m_data, str);
this->m_count++;
}
String(const String& s)
{
/* this->m_data = new char[strlen(s.m_data)+1];
strcpy(this->m_data, s.m_data);*/
this->m_data = s.m_data;
this->m_count++;
}
String& operator=(const String& s)
{
if (this != &s)
{
this->m_data = s.m_data;
/*delete this->m_data;
this->m_data = new char[strlen(s.m_data) + 1];
strcpy(this->m_data, s.m_data);*/
this->m_count++;
}
return *this;
}
~String()
{
if (--this->m_count == 0)//浅拷贝和浅赋值
{
delete[] m_data;
m_data = nullptr;
}
}
public:
void do_uper(char* p)
{
while (*p != '\0')
{
if (*p >= 'a' && *p <= 'z')
{
*p -= 32;
}
p++;
}
}
void to_upper()//写时拷贝,只有在修改对象成员变量时才开辟新空间
{
char* p=NULL;
if (this->m_count > 1)
{
char* tmp = new char [strlen(m_data) + 1];
strcpy(tmp, this->m_data);
this->m_data = tmp;
p = tmp;
this->m_count--;
}
else
{
p = this->m_data;
}
do_uper(p);
}
private:
char* m_data;
static int m_count;
};
int String::m_count = 0;
ostream& operator<<(ostream& cout, const String& s)
{
cout << s.m_data << endl;
return cout;
}
void test01()
{
String s("abc");
}
void test02()
{
String s1("abc");
String s2 = s1;
String s3;
s3 = s1;
cout << s1;
cout << s2;
cout << s3;
}
void test03()
{
String s1("abc");
String s2 = s1;
String s3("xyz");
s1.to_upper();
cout << s1;
cout << s2;
}
int main()
{
//test01();
test03();
system("pause");
return 0;
}
String类的写时拷贝:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
#include<vld.h>
using namespace std;
//#define DISPLAY
class String_rep
{
friend class String;
public:
String_rep(const char* str = "") :m_count(0)
{
#ifdef DISPLAY
cout << "Creat String_Rep Obj" << endl;
#endif
this->m_data = new char[strlen(str) + 1];
strcpy(m_data, str);
}
String_rep(const String_rep& rep)
{
this->m_data = rep.m_data;//浅拷贝
//increament();
}
String_rep& operator=(const String_rep& rep)
{
if (this != &rep)
{
this->m_data = rep.m_data;
//increament();
}
return *this;
}
char* getData()
{
return m_data;
}
~String_rep()
{
#ifdef DISPLAY
cout << "Free String_Rep Obj" << endl;
#endif
delete[] this->m_data;
this->m_data = NULL;
}
void increament()
{
this->m_count++;
}
void decreament()
{
if (--m_count == 0)
{
delete this;//自杀式释放
}
}
private:
char* m_data;
int m_count;
};
class String
{
friend ostream& operator<<(ostream& cout, const String& s);
public:
String(const char* str = "") :pn(new String_rep(str))
{
#ifdef DISPLAY
cout << "Creat String Obj" << endl;
#endif
pn->increament();
}
String(const String& s):pn(s.pn)
{
pn->increament();
}
String& operator=(const String& s)
{
if (this != &s)
{
pn->decreament();
pn = s.pn;
pn->increament();
}
return *this;
}
void to_upper()
{
String_rep* new_pn = new String_rep(pn->m_data);
pn->decreament();
pn = new_pn;
pn->increament();
char* p = pn->m_data;
while (*p != '\0')
{
if (*p >= 'a' && *p <= 'z')
*p -= 32;
p++;
}
}
~String()
{
#ifdef DISPLAY
cout << "Free String Obj" << endl;
#endif
pn->decreament();
}
private:
String_rep* pn;
};
ostream& operator<<(ostream& cout, const String& s)
{
cout << s.pn->getData() << endl;
return cout;
}
void test01()
{
String s1("abc");
//{
// String s1 = s;
//}
String s2 = s1;
String s3("xyz");
}
void test02()
{
String s("abc");
String s1("xyz");
String s2 = s1;
s = s1;
}
void test03()
{
String s1("abc");
String s2 = s1;
String s3 = s2;
cout <<"s1="<< s1;
cout <<"s2="<<s2;
s1.to_upper();
cout <<"s1="<< s1;
cout <<"s2="<< s2;
}
int main()
{
//test01();
test03();
system("pause");
return 0;
}