美文网首页
C++ 学习(5) ---- 深浅拷贝和临时对象

C++ 学习(5) ---- 深浅拷贝和临时对象

作者: 特立独行的佩奇 | 来源:发表于2023-03-27 20:08 被阅读0次

浅拷贝和深拷贝

浅拷贝:
如果用默认的拷贝构造函数去拷构造有指针类型的成员变量的对象,只是会简单的再创建一个指针变量,指针变量的值任然拷贝之前的值;会使两个对象的指针地址也是一样的,也就是说这两个对象的指针成员变量指向的是相同的地址,因为指向同一块内存,容易产生堆区内存重复释放的问题

深拷贝:
深拷贝需要重写拷贝构造和赋值构造函数,重新在堆区申请内存

临时对象

C++ 中容易写出一些代码,这些代码会在程序员不知情的情况下产生一些临时对象,导致临时对象会调用拷贝构造函数,赋值运算符,析构函数,假如该对象还有继承的话,也会调用父类的拷贝构造函数,赋值运算赋函数等,这些临时对象所调用的函数,都是不必要的开销,下面分类讨论下面几种情况

对象做为函数形参

结论:
对象本身做为函数形参,以值传递的方式给函数传参这种方式会直接调用对象的拷贝构造函数,生成一个临时对象传参给函数

当临时对象销毁时候,也是函数形参销毁,也是函数执行完后,就会调用该临时对象的析构函数。此时,无论是调用拷贝构造函数和析构函数,都是额外的开销

代码验证
略,可以定义类时在拷贝构造和析构函数中打印,查看结果

原理
函数调用本身是单向的值传递,在调用函数的时候,实际传递的是实参的复制品,是一个临时对象,不是外面函数的实参,此时在函数内部修改对象,外面的对象本身没有变化

解决方案
只要把值传递的方式修改为引用传递的方式即可

类型转换为临时对象

这种方式就是并且把类型转化前的对象当作了形参传递给构造函数,生成临时对象

定义一个类,重载有一个uint32 类型参数的构造函数和无参构造函数,然后调用形式如下:

{
    baseClass p;
    p = 1000;
}

原理
其实是由于 p = 1000 这句引起的,这里p的类型为 baseClass,而 1000为 int 类型,很明显类型不一致
编译器其实偷偷的进行了类型转换,看编译器的调用都可以发现,其实就是创建一个临时对象,这个临时对象调用了有参构造函数,并且把 这个1000 作为形参,传入有参构造函数,当这个函数调用结束后,对象也就销毁了,所以临时对象会调用析构函数

解决方案
只要把单参数构造函数的复制(复制)语句,改为初始化语句
baseClass p = 1000

函数返回对象

在函数返回对象时候,会创建一个临时对象接收这个对象;从而调用了拷贝构造函数和析构函数
当调用函数时,没有接收返回值时候,就会调用返回值析构函数,因为没有人接收返回值了,自然而然析构了
当调用有接收返回值时候,这个时候,并不会多调用一次析构函数,而是直接把临时对象返回值,给了接受返回值的变量来接收

baseClass testfunction() {
    baseClass a; //baseClass constructor
    return a; // baseClass copy constructor
}

testfunction();//baseClass destructor

上面的函数会调用

demoMain Run ....
baseClass constructor
baseClass copy constructor
baseClass destructor //临时对象的析构
baseClass destructor// 返回值对象的析构

如果修改为下面的调用形式:

baseClass p = testfunction();//baseClass destructor
cout << "output end" << endl;

baseClass constructor
baseClass copy constructor
baseClass destructor  //临时对象析构
output end
baseClass destructor //返回值对象析构

解决方案:
当我们在接收函数返回的对象时候,可以用右值引用接收,因为该函数返回值是一个临时变量,用一个右值引用接收它,使得它的生命周期得以延续,这样就少调用一次析构函数的开销(普通的对象接收也是可以)

当我们在设计函数里的return 语句中,不是返回创建好的对象,而是返回我们临时创建的对象,即使用retturn 类类型(形参); 这个时候,就可以直接避免 return 对象;返回时候又要调用多一次构造函数

baseClass testfunction() {
#if 0
    baseClass a; //baseClass constructor
    return a; // baseClass copy constructor
#else
    return baseClass();
#endif
}

{
    baseClass p = testfunction();//baseClass destructor
    cout << "output end" << endl;
}

相关文章

  • js的深浅拷贝

    js的深浅拷贝可以分为数组的深浅拷贝和对象的深浅拷贝 一、数组的深浅拷贝如果只是简单的将数组中的元素付给另外一个数...

  • Java 最近遇到的面试题

    JAVA 基础 java 对象拷贝深浅拷贝 对象何时进入老年代 Minor GC 和 Full GC 有什么不同 ...

  • 对象深浅拷贝

    关于对象的深浅拷贝,个人有以下几点见解: 1.深拷贝和浅拷贝只针对像Object, Array这样的引用类型数据。...

  • 深浅拷贝 对象

    先定义一个对象 一、浅拷贝 结果:原对象和拷贝后的对象都被修改了! 二、深拷贝 结果:拷贝后的原对象没有被修改,而...

  • 对象深浅拷贝

    浅拷贝 深拷贝

  • c++ 构造函数 几种调用形式

    对于1,按照C++的规定,C c = C();是用默认构造函数创建一个临时对象,并用这个临时对象初始化c(利用拷贝...

  • 前端笔记(二) 对象的深浅拷贝,函数的防抖与节流,函数柯里化 ,

    对象的深浅拷贝 对象的深拷贝与浅拷贝的区别: 浅拷贝:仅仅复制对象的引用, 而不是对象本身。 深拷贝:把复制的对象...

  • 简介深浅拷贝

    深浅拷贝 python 直接赋值,浅拷贝和深拷贝 直接赋值 其实就是对象的引用 (可以理解成浅拷贝) 浅拷贝: 拷...

  • iOS 面试解析|对深浅拷贝的理解

    对深浅拷贝的理解 我们先要理解拷贝的目的:产生一个副本对象,跟源对象互不影响。 深拷贝和浅拷贝的区别 拷贝类型拷贝...

  • JS文集的目录

    js基础心法 深浅拷贝(递归)深浅拷贝(首层浅拷贝) js 数据处理 数组对象查找的常见操作数组对象去重的常见操作...

网友评论

      本文标题:C++ 学习(5) ---- 深浅拷贝和临时对象

      本文链接:https://www.haomeiwen.com/subject/tejnrdtx.html