C++拷贝构造、移动拷贝构造、左值、右值

本文详细介绍了C++中拷贝构造函数、移动构造函数的概念及其对性能的影响。讨论了浅拷贝与深拷贝的区别,以及如何避免浅拷贝带来的内存泄漏问题。此外,还探讨了右值引用、移动构造如何优化性能,并通过实例解释了何时触发移动构造。最后,讲解了完美转发在函数模板中的应用,以及如何实现完美转发的技巧。
摘要由CSDN通过智能技术生成

我们知道C++ 编写程序的一个特点就是需要程序员管理内存,也就是需要的时候new一个对象,在合适的时候释放申请的内存。如果没有释放掉申请的内存会造成内存泄漏,多次释放同一块内存也会造成程序异常。所以对于指针的操作需要特别小心。

C++编写类时,如果类中包含指针成员,就需要特别小心拷贝构造函数的编写,因为很容易造成内存泄漏。例如以下情况:

  • 浅拷贝造成内存泄漏的例子

#include <iostream>
using namespace std;

class HasPtrMem
{
   
public:
	HasPtrMem() :d(new int(0)) {
   }
	//不定义拷贝构造函数时,编译器生产默认拷贝构造函数
	//HasPtrMem(HasPtrMem &rhs) :d(new int(*rhs.d)) {}
	~HasPtrMem() {
    delete d; }
	int *d; //指针成员
};

void main(int argc, char*argv[])
{
   
	HasPtrMem a;
	HasPtrMem b(a); //拷贝构造
	cout << *a.d << std::endl;
	cout << *b.d << std::endl;
}

首先定义一个包含指针成员的HasPtrMem类。在构造函数中申请内存,在析构函数中释放内存。
然后在main函数中申明一个HasPtrMem变量a, 并用a初始化变量b,
类没有定义拷贝构造函数时,编译器会隐式地(隐式表示如果不被使用则不生成)生成拷贝构造函数,在拷贝构造函数中对成员变量执行类似于memcpy的按位复制。执行默认拷贝函数后,指针成员变量会指向同一块堆内存。
在本例中的两个HasPtrMem对象a,b中的指针都指向了同一块推内存,在析构函数中两次释放内存时就会造成异常。
本例中两个对象的拷贝方式也就是浅拷贝,如果改成深拷贝就不会出现异常了。

  • 深拷贝例子
#include <iostream>
using namespace std;

class HasPtrMem
{
   
public:
	HasPtrMem() :d(new int(0)) {
   }
	HasPtrMem(HasPtrMem &rhs) :d(new int(*rhs.d)) {
   }// 复制构造函数;深拷贝
	~HasPtrMem() {
    delete d; }
	int *d;
};

void main(int argc, char*argv[])
{
   
	HasPtrMem a;
	HasPtrMem b(a);
	cout << *a.d << std::endl;
	cout << *b.d << std::endl;
}

浅拷贝 && 深拷贝

  • 浅拷贝(shallow copy)

增加一个指针,指向一个已经纯在的内存。实现了逻辑上的拷贝。

  • 深拷贝(deep copy)

新申请一块内存,并把数据拷贝到新的内存。实现逻辑和物理上的拷贝。

浅拷贝造成的内存泄漏问题,解决办法有

  1. 可以修改拷贝构造函数和赋值操作符,实现深拷贝。
  2. 使用智能指针share_ptr,通过引用计数解决重复释放内存问题。

拷贝影响性能

除了复制对象时调用拷贝构造函数外,还有以下情况
1) 函数参数为对象,实参传递给形参的实际上是拷贝对象。
2) 函数的返回值为对象,实际是函数内对象的一个拷贝,用于返回函数调用处。

例如以下情况


#include <iostream>
using namespace std;

class HasPtrMem
{
   
public:
	HasPtrMem() :d(new int(0)) {
    std::cout << "construct: " << ++n_constructor << std::endl; }
	HasPtrMem(HasPtrMem &rhs) :d(new int(*rhs.d)) // 拷贝构造函数,深拷贝
	{
   
		std::cout << "copy construct: " << ++n_copyConstructor << std::endl;
	}
	~HasPtrMem() {
   
		delete d; 
		std::cout << "destruct: " << ++n_destructor << std::endl;
	}
	int *d;

	static int n_constructor;
	static
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值