好久之前学的了,在CLion上试一下,发现为什么用的浅拷贝还是可以正常运行,于是转到了CB,发现还是可以正常运行,最后用了VS2022,就不行。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
//默认复制函数带来的问题
using namespace std;
class String
{
public:
char* str;
int len;
public:
String(const char* s)
{
len = strlen(s);
str = new char[len + 1];
strcpy(str,s);
}
String(String& s)
{
len = s.len;
str = new char[len + 1]; //深拷贝,在堆区创建副本,delete的时候释放的是这个堆区的副本,不会影响原本
strcpy(str, s.str);
cout << "拷贝构造函数的调用" << endl;
}
~String()
{
cout << "析构函数的调用" << endl;
delete[]str;
}
};
void usevalue(String s)
{
cout << s.str << endl;
}
int main()
{
String s = "hello world";
cout << s.str << endl;
usevalue(s);
cout << s.str << endl;
return 0;
}
浅拷贝就是临时的副本复制的是直接复制原本,delete的时候影响了原本,因为浅拷贝是直接复制,副本中的指针和原本中的指针指向的是同一块地方,做深拷贝改进。
另外在进行类的复制运算时要想清怎样设计这个类,例如
String a,b;
a = "hello world";
b = a;
这样我们感觉是没有问题的,但其实他是有点问题的,同样是浅拷贝造成的安全隐患,a与b中的指针指向的是同一块地方,我们可能在对b操作的时候误操作到了a,这也需要设计一个 重载= 来进行深拷贝赋值。
最明显的一个错误:当程序结束时,会重复释放a,b指向的内存造成错误
String & operator=(const String &s)
{
if(this.str == s.str)
return this;
delete [] str;
len = s.len;
str = new char[len + 1];
strcpy(str,s.str);
return *this;
}
同样,这就需要我们也对默认构造函数改进以下,这里就不陈述了。
先释放原有的内容,再进行新串的赋值,返回引用是为了链式链接,即可以连等
String a,b,c;
a = "C++";
c = b = a; //if return reference OK