设计一个字符串类,下面的代码是一个不好的设计,起名StringBad。
//stringbad.h
#pragma once
//一个设计有问题的string类
#include <iostream>
using namespace std;class StringBad
{
public:StringBad();//默认构造函数StringBad(const char* s);//构造函数~StringBad();//析构函数friend ostream& operator<<(ostream& os, const StringBad& s);//友元函数,输出函数
private:char* str;//指向保存的字符串int len;//字符串的长度static int num_strings;//创建的对象数量
};
//stringbad.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "stringbad.h"
#include <cstring>int StringBad::num_strings = 0;//类中的变量StringBad::StringBad()//默认构造函数
{len = strlen("趣字节");str = new char[len + 1];//动态创建内存,用于存放默认字符串strcpy(str,"趣字节");num_strings++;//对象数量+1cout << "默认构造函数," << str << ",对象数量:" << num_strings << endl;//不重要的输出
}StringBad::StringBad(const char* s)//构造函数
{len = strlen(s);str = new char[len + 1]; //动态创建内存,用于存放传入的字符串sstrcpy(str,s);num_strings++;//对象数量+1cout << "构造函数," << str << ",对象数量:" << num_strings << endl;//不重要的输出
}StringBad::~StringBad()
{cout << "析构函数," << str; //不重要的输出delete[]str; //释放动态内存str = NULL;len = 0;num_strings--;//对象数量-1cout << ",对象数量:" << num_strings << endl;//不重要的输出
}ostream& operator<<(ostream& os, const StringBad& s)//友元函数,输出函数
{os << s.str << endl;return os;
}
测试程序如下:
#include"stringbad.h"int main()
{StringBad s1("趣字节,有趣的编程!!!");cout << "s1:" << s1;cout << "-------------" << endl;StringBad s2 = s1;cout << "s2:" << s1;cout << "-------------" << endl;StringBad s3;s3 = s1;cout << "s3:" << s3;return 0;
}
程序运行崩溃,并提示错误
上面的代码在构造s2时已经出错(s3也有问题),构造s2时并没有调用构造函数,后面在析构s2时程序直接崩溃。这就是常说的浅拷贝导致的问题。
C++提供下面这些默认函数(如果您没有提供):
●默认构造函数。不接受参数也不执行任何操作。
●默认析构函数,不执行任何操作。
●拷贝(复制)构造函数。用对象初始化另一个新建对象,逐个复制非静态成员,复制的是成员的值(浅复制)。
●拷贝赋值运算符。用对象赋值给另一个对象,逐个复制非静态成员,复制的是成员的值(浅复制)。
●移动构造函数。C++11增加。
●移动赋值运算符。C++11增加。
●地址运算符。返回对象的地址。和我们想象一致,不再讨论。
使用默认拷贝构造函数和使用默认=赋值运算符,导致浅拷贝,在析构时会出现重复释放(delete)同一段内存,导致程序崩溃。
解决的办法:自己定义拷贝构造函数和赋值=运算符重载函数,实现深拷贝。