C++之深浅拷贝
来源:互联网 发布:mysql create trigger 编辑:程序博客网 时间:2024/05/20 06:24
我们都知道,在C++中会用一个类变量构造同类变量时会用到拷贝构造函数。对于一般变量,我们在使用过程中并没有什么问题,定义也非常简单,一般我们所使用的都是浅拷贝,其实浅拷贝和深拷贝各有各的好处:
浅拷贝节省空间,但有时会出错,深拷贝更加安全,但有时候会造成不必要的空间浪费。
观察下面函数:
//如果Test类只有一个data值时:Test(const Test &t){ data = t.data;}
显而易见,这个函数并没有什么错误,也能完成它的功能。但是,我们看下下面的例子,如果用浅拷贝整个程序运行通过不了了:
#include <iostream>#include <malloc.h>#include <string.h>using namespace std;class String{public: String(const char *str = NULL) { cout << "String()!!" << endl; if(str == NULL){ data = (char *)malloc(sizeof(char)); data[0] = '\0'; }else{ data = (char *)malloc(strlen(str) + 1); strcpy(data, str); } } String(const String &str) { cout << "String(const String &str)!!" << endl; data = str.data; } char *GetData() { return this->data; } ~String() { cout << "~String()!!" << endl; free(data); }private: char *data;};int main(){ String str("Hello"); //构造函数 String str1; str1 = str; //赋值运算 String str2(str); //拷贝构造 cout << "str = " << str.GetData() << endl; cout << "str1 = " << str1.GetData() << endl; cout << "Str2 = " << str2.GetData() << endl; return 0;}
运行发现程序core dumped。
很容易发现,程序调用了两次构造函数,一次拷贝构造函数,但析构了两个然后就core dumped了。这就是因为浅拷贝的问题:
在拷贝构造时,我们只是浅拷贝让str1的data指向了str的data空间,虽然是两个不同String变量,但内部data实际上指向的时同一空间,但是程序结束时,str和str1分别调用析构函数来释放它们内部的data值,这样该空间被释放了两次,所以程序运行到最后崩溃。
这里,我们解决的方法是,在String类中增加一个use_count计数值,让它记录指向data的变量个数。如果浅拷贝一次,use_count++,如果要改变某一个变量中的data值,先判断它的use_count值,如果只有它一个指向data时,直接更改,否则,要先对他进行深拷贝同时给use_count-1,然后在对它拷贝来的data值进行修改。析构同理,当use_count减为1时在析构,下面是代码实现:
#include <iostream>#include <stdio.h>#include <string.h>#include <malloc.h>using namespace std;class String;ostream& operator<<(ostream &out, const String &s);class String_rep{ friend class String; friend ostream& operator<<(ostream &out, const String &s);public: String_rep(const char *str = ""):use_count_(0) { data = new char[strlen(str) + 1]; strcpy(data, str); } String_rep(const String_rep &s); String_rep& operator=(const String_rep &s) { //if(this != &s){ // data = s.rep->data; //increment(); //} return *this; } ~String_rep() { delete data; }public: void increment(){++use_count_;} void decrement() { //--use_count_; if(--use_count_ == 0){ delete this; } } int use_count() const { return use_count_; }private: char *data; int use_count_;} ;class String{ friend ostream& operator<<(ostream &out, const String &s);public: String(const char *str = "") : rep(new String_rep(str)) { rep->increment(); } String(const String &s) { rep = s.rep; rep->increment(); } String& operator=(const String &s) { if(this != &s){ rep->decrement(); rep = s.rep; rep->increment(); } return *this; } ~String() { //int i = this->use_count; //if((--(rep->use_count_)) == 1){ //free(rep->data); //delete rep; //} rep->decrement(); }public: int use_count() const { return rep->use_count(); } void to_upper() { char *ch = rep->data; if(this->use_count() == 1){ while(*ch != '\0'){ *ch -= 32; ch ++; } }else{ (rep->use_count_) --; rep = new String_rep(rep->data); strcpy(rep->data, ch); (rep->use_count_)++; ch = rep->data; while(*ch != '\0'){ *ch -= 32; ch ++; } } }private: String_rep *rep;}s;ostream& operator<<(ostream &out, const String &s){ out << (s.rep)->data; return out;}int main(){ String s1("abcd"); cout << "s1 = " << s1; cout << " s1 use_count = " << s1.use_count() << endl; String s2 = s1; cout << endl << "s2 = " << s2; cout << " s2 use_count = " << s2.use_count() << endl; String s3; s3 = s1; cout << endl << "s3 = " << s3; cout << " s3 use_count = " << s3.use_count() << endl; s2.to_upper(); cout << endl << "s1 = " << s1; cout << " s1 use_count = " << s1.use_count() << endl; cout << "s2 = " << s2; cout << " s2 use_count = " << s2.use_count() << endl; cout << "s3 = " << s3; cout << " s3 use_count = " << s3.use_count() << endl; }
运行结果;
在拷贝构造时,深拷贝、浅拷贝各有千秋,我们只有恰当的使用它们,才能程序消耗空间尽可能小而且稳定。
0 1
- Objective-c 深浅拷贝
- 【C++】 浅析深浅拷贝
- C++String深浅拷贝
- Python之深浅拷贝
- C++之深浅拷贝
- C++之深浅拷贝
- Python之深浅拷贝
- 【C/C++】浅谈C/C++之深浅拷贝
- Objective-C 深浅拷贝学习
- [解析]Objective-C 深浅拷贝
- C++String深浅拷贝问题
- 浅析Objective-C 深浅拷贝
- c++-----string和深浅拷贝
- IOS学习之深浅拷贝
- iOS基础之----深浅拷贝
- iOS开发之深浅拷贝
- Python学习之深浅拷贝
- js对象之深浅拷贝
- 【hdu2087】剪花布条——KMP
- C++实现内存复制函数(memmove解决内存重叠)
- operator关键字(重载操作符)
- Android API Guides---Input Events
- 数据库三大范式的一己之见
- C++之深浅拷贝
- 蛇形数组分析
- ActionBar
- windows可执行文件调用jar包执行java程序-toolsRun.bat
- View的属性值
- Java学习之集合框架
- Android基础总结--软键盘windowSoftInputMode
- 显示联系人列表1_(demo)
- WUST OJ 1579 Camellia(数位dp)