C++复制与拷贝构造函数

拷贝

除了引用以外,当一个变量赋值给另一个变量时,都是在拷贝。
可能是在拷贝指针(地址),也可能是在拷贝对象。

struct Vector2
{
    float x,y;
};

int main()
{
    // 拷贝对象
    Vector2 v1 = {1,1};
    Vector2 v2 = v1;
    v2.x = 2;
    cout<< v1.x<<endl;	// 输出1,v1v2是不同对象
    
    // 拷贝指针
    Vector2* p1 = new Vector2();
    Vector2* p2 = p1;
    p2->x = 3;
    cout<< p1->x<<endl; // 输出3,p1和p2操作的是同一对象
}

拷贝的缺点是慢,因此如果不需要新生成一样的变量的话应该避免拷贝。

浅拷贝

一种不完全的拷贝。所有成员的直接拷贝,但对指针来说,并不会拷贝内容,只是指针拷贝(两个指针指向相同地址)。这就是浅拷贝的缺点:这种情况下,通过一个指针改变内容,另一个指针的内容也会改变,一个指针删除,另一个指针会出错。但实际上我们希望对象拷贝的时候,新的指针会指向新的内存空间,并复制旧指针的内容。

如下自定义了一个字符串类,在main中进行字符串拷贝。

class String
{
private:
    char* m_Buffer;
    unsigned int m_Size;
public:
    String(const char* string)
    {
        m_Size = strlen(string);
        m_Buffer = new char[m_Size+1];
        memcpy(m_Buffer, string, m_Size);
        m_Buffer[m_Size] = 0;
    }
    ~String()
    {
        delete[] m_Buffer;
    }
    // 用于按索引取字符
    char& operator[](unsigned int index)
    {
        return m_Buffer[index];
    }
    // cout能够直接输出private成员
    friend ostream& operator<< (ostream& stream, const String& string);
};

ostream& operator<< (ostream& stream, const String& string)
{
    stream << string.m_Buffer;
    return stream;
}

int main()
{
    String str1("chen");
    String str2 = str1;
    str2[2] = 'a';
    cout<< str1<<endl;// chan
    cout<< str2<<endl;// chan
    
}

这里你不光可以发现str2的修改直接影响了str1,你还得到了一个crush😘(对不起是crash)。原因是如果没有实现拷贝函数,c++默认拷贝方式是所有成员的赋值拷贝,这意味着char*只是拷贝了一个指针地址,导致str1和str2指向相同地址。这使得一个修改导致同时修改,并且crash是因为delete同一个char*两次。

深拷贝

不是表层的简单复制,还会为指针开辟新区域去复制。实现深拷贝,需要根据具体成员类型实现拷贝构造函数。

拷贝构造函数

在用拷贝方式创建新对象时调用。C++提供了默认的拷贝构造,但需要重写该函数。

对于上述例子,默认拷贝构造类似于:

String(const String& other)
        :m_Buffer(other.m_Buffer), m_Size(other.m_Size){}

如果不允许拷贝,则用如下方式:

String(const String& other) = delete

深拷贝则写为:

String(const String& other)
	:m_Size(other.m_Size)
{
    m_Buffer = new char[m_Size+1];
    memcpy(m_Buffer, other.m_Buffer, m_Size+1);
}

避免拷贝

如之前所说,拷贝会多占用内存,影响性能。在不需要拷贝的情况下尽量避免拷贝。

void Print(const String& str)
{
    cout<< str<< endl;
}

正常情况下,对对象的修改都是由对象的成员函数完成的。类外函数不会修改对象,所以在对象为参数时,永远以const<type>&为参数类型传递,避免对象的复制

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中,复制构造函数和拷贝构造函数是指用于创建一个新对象并将其初始化为现有对象的构造函数。复制构造函数和拷贝构造函数的作用是相同的,它们都用于将一个对象的值复制给另一个对象。通常情况下,复制构造函数用于通过值传递或返回对象,而拷贝构造函数用于通过引用传递对象。 在引用中提到,当一个类拥有其他资源时(如动态分配内存、打开文件、指向其他数据的指针、网络连接等),默认的拷贝构造函数无法拷贝这些资源,因此必须显式定义一个拷贝构造函数来完成对象的完整拷贝。 在引用中提到,拷贝构造函数可以有多个,并且可以使用不同的参数类型。当一个构造函数的第一个参数是类本身的引用时,它被认为是一个拷贝构造函数。使用引用作为参数的原因有两点:一是为了提高效率,避免不必要的拷贝;二是为了避免死循环,在对象需要以值方式传递时,编译器会生成代码调用拷贝构造函数以生成一个复本,如果没有使用引用作为参数,就会导致死循环。 以下是一个示例代码,展示了如何定义和使用拷贝构造函数: #include <iostream> using namespace std; class Test { public: Test(); ~Test(); Test(const Test& t); Test& operator=(const Test& t); private: int t1; }; Test::Test() { cout << "调用构造函数" << endl; } Test::~Test() { cout << "调用析构函数" << endl; } Test::Test(const Test& t) { cout << "调用拷贝构造函数" << endl; } Test& Test::operator=(const Test& t) { cout << "调用赋值构造函数" << endl; t1 = t.t1; return *this; } int main() { Test t1; Test t2 = t1; // 使用拷贝构造函数创建新对象t2 Test t3; t3 = t1; // 使用赋值构造函数将t1的值赋给t3 return 0; } 输出结果为: 调用构造函数 调用拷贝构造函数 调用构造函数 调用赋值构造函数 调用析构函数 调用析构函数 以上代码中,Test类定义了一个拷贝构造函数和一个赋值构造函数。在main函数中,我们创建了一个t1对象,并使用拷贝构造函数将其值复制给t2对象。然后我们再创建一个t3对象,并使用赋值构造函数将t1的值赋给t3对象。在程序结束时,析构函数会被调用来释放对象占用的资源。 希望以上解答对你有所帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++ 之构造函数(拷贝/复制构造函数)](https://blog.csdn.net/qq_45856289/article/details/106967212)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [C++复制构造函数和拷贝构造函数](https://blog.csdn.net/hongkangwl/article/details/20462019)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值