【C语言】【面试题】C++中String类浅拷贝,深拷贝的传统写法与现代写法

时间:2022-06-06 21:22:42

C++ 的一个常见面试题是让你实现一个 String 类,在这我把String类的各种写法写了一下

    1.浅拷贝

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//1.浅拷贝
class String
{
public:
    String(char* str)
        :_str(str)
    {}

    String(const String& s)
        :_str(s._str)
    {}

    //~String()
    //{
    //    delete[] _str;
    //} 不能释放两次,无论是构造函数还是,拷贝构造都只是把指针指向同一块空间
private:
    char* _str;

};

void Test1()
{
    String s1("s1");
    String s2(s1);
}

int main()
{
    Test1();
    
    system("pause");
    return 0;
}

    对于浅拷贝如果我们不写析构函数的话,这种写法是没有错误的,但是一旦写上析构函数,就会有问题了,因为这种写法像如果像测试函数Test1写的那样,就会释放两次s1指向的空间,程序就会崩溃,如果想更完善,就需要一种更健全的方法。

    

    2.深拷贝-->传统写法

这种写法的优点在于:在构造和拷贝构造时都重新开辟了空间,无论析构多少次程序都不会奔溃,而且可在操作性有所提高

class String{public:    /*String()        :_str(new char[1])    {        _str[0] = '\0';    }*/    String(char* str = "")        :_str(new char[strlen(str) + 1])    {        strcpy(_str, str);    }    String(const String& s)        :_str(new char[strlen(s._str) + 1])    {        strcpy(_str, s._str);    }    String& operator=(const String&s) //重载写法1,不完善    {        if (this != &s)        {            delete[] _str;            _str = new char[strlen(s._str) + 1];            strcpy(_str, s._str);        }        return *this;    }    String& operator=(const String& s)//重载写法2,思路更健全    {        char* tmp = new char[strlen(s._str) + 1];        strcpy(tmp, s._str);      delete[] _str;        _str = tmp;    }    ~String()    {        /*if (_str)*/        delete[] _str;    } private:    char* _str;};void Test1(){    String s1("s1");    //String s3();    String s2(s1);}int main(){    Test1();    system("pause");    return 0;}

传统写法是根据大多数人的思路走的,这样写出来的程序可读性高,这个写法主要是两种重载的写法,第一种没有考虑new是否能开辟出足够大小的空间,就直接释放了原来的_str,第二种写法就是反过来先申请空间然后再释放,这种思路更严谨一些。

    

    3.深拷贝-->现代写法

现代写法是基于传统写法上改进的,代码更简洁高效,只是逻辑变得更复杂了。

class String{public:    String(char* str = "")        :_str(new char[strlen(str) + 1])    {        strcpy(_str, str);    }    String(const String& s)        :_str(NULL)    {        String tmp(s._str);        swap(_str, tmp._str);    }    String& operator=(String s)//针对已经存在的两个字符串类型 所以直接交换即可   隐试生成一块临时空间,交换后把可把原来的空间释放掉    {        swap(_str, s._str);        return *this;    }    ~String()    {        /*if (_str)*/        delete[] _str;    }private:    char* _str;};void Test1(){    String s1("s1");    //String s3();    String s2(s1);}int main(){    Test1();    system("pause");    return 0;}

总结传统写法和现代写法:

    传统写法:1.可读性高,符合人的正常思维

    现代写法:1.简洁 2.new/delete都在统一的地方,可维护性高