Loading

C++ 深拷贝浅拷贝

深拷贝用来解决浅拷贝造成的两次析构问题,因为浅拷贝时,两个指针指向同一块内存空间,析构时,一块内存空间释放两次,系统会报错。因此,我们需要重新开辟一块内存空间,使两个指针指向不同的空间,以此来解决问题。

下面用一个String的例子来验证深拷贝。

#include <iostream>
#include <cstring>
using namespace std;
class String
{
public:
    //利用列表初始化为mPstr在堆上创建一个内存空间
    String(const char *s = " ") : mPstr(new char[strlen(s) + 1]) 
    {
        strcpy(mPstr,s);
    }
    //默认拷贝构造函数中,s1和s2指向同一块内存空间,当析构时,先析构s2,内存空间已经销毁,再销毁一次s1,两次析构同一个空间,报错。
    //因此,需要重新开辟一块内存空间,让s2指向新空间,析构时,各删各的
    String(const String &other) : mPstr(new char[strlen(other.mPstr) + 1]) 
    {
        strcpy(mPstr, other.mPstr);
    }

    ~String()
    {
        delete []mPstr;
    }

    void show() const
    {
        cout << mPstr << endl;
    }

    void append(const String &other)  //实现一个追加功能
    {
        char *p = new char[strlen(this->mPstr) + strlen(other.mPstr) + 1];
        strcpy(p, this->mPstr);
        strcat(p, other.mPstr);
        delete []this->mPstr;
        mPstr = p;
        //因为p是局部变量,所以不需要手动销毁
    }

    void assign(const String &other) //实现一个覆盖功能
    {
        if(this != &other)           //如果覆盖的字符是本身,就不覆盖
        {
        char *p = new char[strlen(other.mPstr) + 1];
        strcpy(p, other.mPstr);
        delete []this->mPstr;
        mPstr = p;
        }
    }

private:
    char *mPstr;
};

int main(void)
{
    String s1("Hello");
    s1.show();
    String s2(s1);
    s2.show();
    system("pause");
    return 0;
}

再来一个链表的例子

#include <iostream>
#include <cstring>
using namespace std;
//链表
struct Node  //定义结点,实际上还是一个类,所以可以使用列表初始化
{
    Node(int value, Node *pNext) : data(value), next(pNext){}
    int data;
    Node *next;
};

class List
{
public:
    List();
    //默认拷贝构造函数,会导致浅拷贝的问题,在析构时,删除同一块内存空间,报错,因此将新的pHead置空,复制数据,重新插入
    List(const List &other);
    ~List();
    void push_front(int value); //在头部插入数据
    void push_back(int value);  //在尾部插入数据
    void pop_front();           //删除头部数据
    void pop_back();            //删除尾部数据
    void clear();               //清空数据,用于析构
    void show() const;          //打印链表数据
    size_t size() const;        //记录结点个数
    bool isEmpty() const;       //判空函数
private:
    Node *pHead;                
};

int main(void)
{
    List l;
    l.push_front(1);
    l.push_front(2);
    l.push_front(3);
    l.show();
    cout << "***********" << endl;
    List l2(l);
    l2.show();
    system("pause");
    return 0;
}

List::List() : pHead(nullptr)
{

}

List::List(const List &other) : pHead(nullptr)
{
  Node *p = other.pHead;
  while(p)
  {
      this->push_back(p->data);
      p = p->next;
  }
}

List::~List()
{
   clear();
}

void List::push_front(int value)
{
    Node *pNew = new Node(value, pHead);
    pHead = pNew;
}

bool List::isEmpty() const
{
    return nullptr == pHead;
}

void List::push_back(int value)
{
    if(isEmpty())
    {
        push_front(value);
    }
    else
    {
        Node *pNew = new Node(value, nullptr);
        Node *p = pHead;
        while(p->next)
        {
            p = p->next;
        }
        p->next = pNew;
    }
}

void List::pop_front()
{
    if(!isEmpty())
    {
        Node *p = pHead;
        pHead = p->next;
        delete p;
    }

}

void List::pop_back()
{
    if(!isEmpty())
    {
        size_t n = size();
        if(n == 1)
        {
            pop_front();
        }
        if(n >= 2)
        {
            Node *p = pHead;
            while(p->next->next != 0)
            {
                p = p->next;
            }
            delete p->next;
            p->next = nullptr;
        }
    }

}

void List::show() const
{
    Node *p = pHead;
    while(p)
    {
        cout << p->data << endl;
        p = p->next;
    }
}

void List::clear()
{
    while(!isEmpty())
    {
        pop_front();
    }
}

size_t List::size() const
{
    Node *p = pHead;
    size_t counter = 0;
    while(p)
    {
        ++counter;
        p = p->next;
    }
    return counter;
}
posted @ 2020-09-28 22:31  小森林呐  阅读(235)  评论(0编辑  收藏  举报