zl程序教程

您现在的位置是:首页 >  .Net

当前栏目

C++笔记(5)浅拷贝和深拷贝

2023-02-18 16:27:15 时间

1. 定义

浅拷贝(shallow copy):多个对象共用同一块资源,同一块资源释放多次,崩溃或者内存泄漏

深拷贝(deep copy):每个对象共同拥有自己的资源,必须显式提供拷贝构造函数和赋值运算符。

2. 示例

(书p355)

#include <iostream>
using namespace std;
//类声明
class String
{
private:
    char* str;
    int len;
    static int num_strings;
public:
    String(const char* s);
    String();
    ~String();
    friend std::ostream& operator<<(std::ostream& os, const String& s);
};

//不能在类声明中初始化静态成员变量
int String::num_strings = 0;
String::String(const char* s)
{
    len = strlen(s);
    str = new char[len + 1];
    strcpy_s(str, strlen(s) + 1, s);
    num_strings++;
    cout << "num_strings:\"" << str << "\"object created\n";
}

//类实现
String::String()
{
    len = 4;
    str = new char[len + 1];
    strcpy_s(str, 4, "c++");
    num_strings++;
    cout << "num_strings:\"" << str << "\"object created\n";
}

String::~String()
{
    cout << "num_strings:\"" << str << "\"object deleted\n";
    num_strings--;
    cout << num_strings << " object left\n";
    delete[] str;
}

std::ostream& operator<<(std::ostream& os, const String& s)
{
    os << s.str << ":" << int(s.str) << endl;
    return os;
}

//主函数
int main() {
    {
        String s1 = "aaaa";
        cout << s1;
        String s2 = s1;
        cout << s2;
    }
    cout << "End of main()!\n";
    return 0;
}

运行中断:

num_strings:"aaaa"object created
aaaa:16857352
aaaa:16857352
num_strings:"aaaa"object deleted
0 object left
num_strings:"葺葺葺葺葺葺葺葺?b@?"object deleted
-1 object left

默认的拷贝构造函数逐个复制非静态成员(浅拷贝),复制的是成员的值。

String s2 = s1;

相当于:

String s2;
s2.str = s1.str;
s2.len=s1.len;

其中,s2.str = s1.str复制的不是字符串,而是指向字符串的指针。也就是说,将s2初始化为是s1后,得到两个指针指向一个字符串。析构函数释放了s2.str指针指向的内存,因此在释放s2时,导致了不确定,可能有害的结果。

  解决这类设计中这种问题的方法是进行深拷贝(deep copy)。也就是说,拷贝构造函数应该复制字符串并将副本的地址赋给str成员,而不仅仅是复制字符串地址这样每个对象都有自己的字符串,而不会试图去释放已经被释放的字符串。

可以定义一个显式拷贝构造函数以解决问题:

String::String(const String& st) {
    len = st.len;
    str = new char[len + 1];
    strcpy_s(str, len+1, st.str);
    num_strings++;
    cout << "num_strings:\"" << str << "\"object created\n";
}

运行结果:

num_strings:"aaaa"object created
num_strings:"aaaa"object created
num_strings:"aaaa"object deleted
1 object left
num_strings:"aaaa"object deleted
0 object left
End of main()!

3. 总结

如果类中包含了使用new初始化的指针成员,应当定义一个拷贝构造函数,以复制指向的数据,而不是指针。