iis服务器助手广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++11中移动构造函数案例代码
  • 477
分享到

C++11中移动构造函数案例代码

C++11移动构造函数C++11构造函数C++构造函数 2023-01-04 12:01:58 477人浏览 薄情痞子
摘要

目录1. 拷贝构造函数中的深拷贝问题2. c++移动构造函数(移动语义的具体实现)1. 拷贝构造函数中的深拷贝问题 在 C++ 98/03 标准中,如果想用其它对象初始化一个同类的新

1. 拷贝构造函数中的深拷贝问题

在 C++ 98/03 标准中,如果想用其它对象初始化一个同类的新对象,只能借助类中的拷贝构造函数。拷贝构造函数的实现原理很简单,就是为新对象复制一份和其它对象一模一样的数据。需要注意的是,当类中拥有指针类型的成员变量时,拷贝构造函数中需要以深拷贝(而非浅拷贝)的方式复制该指针成员。

举个例子:

#include <iOStream>
using namespace std;

class demo{
public:
   demo():num(new int(0)){
      cout<<"construct!"<<endl;
   }
   //拷贝构造函数
   demo(const demo &d):num(new int(*d.num)){
      cout<<"copy construct!"<<endl;
   }
   ~demo(){
      cout<<"class destruct!"<<endl;
   }
private:
   int *num;
};

demo get_demo(){
    return demo();
}

int main(){
    demo a = get_demo();
    return 0;
}

如上所示,我们为 demo 类自定义了一个拷贝构造函数。该函数在拷贝 d.num 指针成员时,必须采用深拷贝的方式,即拷贝该指针成员本身的同时,还要拷贝指针指向的内存资源。否则一旦多个对象中的指针成员指向同一块堆空间,这些对象析构时就会对该空间释放多次,这是不允许的。

可以看到,程序中定义了一个可返回 demo 对象的 get_demo() 函数,用于在 main() 主函数中初始化 a 对象,其整个初始化的流程包含以下几个阶段:

  • 执行 get_demo() 函数内部的 demo() 语句,即调用 demo 类的默认构造函数生成一个匿名对象;
  • 执行 return demo() 语句,会调用拷贝构造函数复制一份之前生成的匿名对象,并将其作为 get_demo() 函数的返回值(函数体执行完毕之前,匿名对象会被析构销毁);
  • 执行 a = get_demo() 语句,再调用一次拷贝构造函数,将之前拷贝得到的临时对象复制给 a(此行代码执行完毕,get_demo() 函数返回的对象会被析构);
  • 程序执行结束前,会自行调用 demo 类的析构函数销毁 a。

注意,目前多数编译器都会对程序中发生的拷贝操作进行优化,因此如果我们使用 VS 2017、codeblocks 等这些编译器运行此程序时,看到的往往是优化后的输出结果:

construct!
class destruct!

而同样的程序,如果在 linux 上使用g++ demo.cpp -fno-elide-constructors命令运行(其中 demo.cpp 是程序文件的名称),就可以看到完整的输出结果:

construct!        <-- 执行 demo()
copy construct!    <-- 执行 return demo()
class destruct!     <-- 销毁 demo() 产生的匿名对象
copy construct!    <-- 执行 a = get_demo()
class destruct!     <-- 销毁 get_demo() 返回的临时对象
class destruct!     <-- 销毁 a

如上所示,利用拷贝构造函数实现对 a 对象的初始化,底层实际上进行了 2 次拷贝(而且是深拷贝)操作。当然,对于仅申请少量堆空间的临时对象来说,深拷贝的执行效率依旧可以接受,但如果临时对象中的指针成员申请了大量的堆空间,那么 2 次深拷贝操作势必会影响 a 对象初始化的执行效率。

事实上,此问题一直存留在以 C++ 98/03 标准编写的 C++ 程序中。由于临时变量的产生、销毁以及发生的拷贝操作本身就是很隐晦的(编译器对这些过程做了专门的优化),且并不会影响程序的正确性,因此很少进入程序员的视野。

那么当类中包含指针类型的成员变量,使用其它对象来初始化同类对象时,怎样才能避免深拷贝导致的效率问题呢?C++11 标准引入了解决方案,该标准中引入了右值引用的语法,借助它可以实现移动语义。

2. C++移动构造函数(移动语义的具体实现)

所谓移动语义,指的就是以移动而非深拷贝的方式初始化含有指针成员的类对象。简单的理解,移动语义指的就是将其他对象(通常是临时对象)拥有的内存资源“移为已用”。

以前面程序中的 demo 类为例,该类的成员都包含一个整形的指针成员,其默认指向的是容纳一个整形变量的堆空间。当使用 get_demo() 函数返回的临时对象初始化 a 时,我们只需要将临时对象的 num 指针直接浅拷贝给 a.num,然后修改该临时对象中 num 指针的指向(通常另其指向 NULL),这样就完成了 a.num 的初始化。

事实上,对于程序执行过程中产生的临时对象,往往只用于传递数据(没有其它的用处),并且会很快会被销毁。因此在使用临时对象初始化新对象时,我们可以将其包含的指针成员指向的内存资源直接移给新对象所有,无需再新拷贝一份,这大大提高了初始化的执行效率。

例如,下面程序对 demo 类进行了修改:

#include <iostream>
using namespace std;

class demo{
public:
    demo():num(new int(0)){
        cout<<"construct!"<<endl;
    }
    demo(const demo &d):num(new int(*d.num)){
        cout<<"copy construct!"<<endl;
    }
    //添加移动构造函数
    demo(demo &&d):num(d.num){
        d.num = NULL;
        cout<<"move construct!"<<endl;
    }
    ~demo(){
        cout<<"class destruct!"<<endl;
    }
private:
    int *num;
};

demo get_demo(){
    return demo();
}

int main(){
    demo a = get_demo();
    return 0;
}

可以看到,在之前 demo 类的基础上,我们又手动为其添加了一个构造函数。和其它构造函数不同,此构造函数使用右值引用形式的参数,又称为移动构造函数。并且在此构造函数中,num 指针变量采用的是浅拷贝的复制方式,同时在函数内部重置了 d.num,有效避免了“同一块对空间被释放多次”情况的发生。

在 Linux 系统中使用g++ demo.cpp -o demo.exe -std=c++0x -fno-elide-constructors命令执行此程序,输出结果为:

construct!
move construct!
class destruct!
move construct!
class destruct!
class destruct!

通过执行结果我们不难得知,当为 demo 类添加移动构造函数之后,使用临时对象初始化 a 对象过程中产生的 2 次拷贝操作,都转由移动构造函数完成。

我们知道,非 const 右值引用只能操作右值,程序执行结果中产生的临时对象(例如函数返回值、lambda 表达式等)既无名称也无法获取其存储地址,所以属于右值。当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数。

在实际开发中,通常在类中自定义移动构造函数的同时,会再为其自定义一个适当的拷贝构造函数,由此当用户利用右值初始化类对象时,会调用移动构造函数;使用左值(非右值)初始化类对象时,会调用拷贝构造函数。

那么,如果使用左值初始化同类对象,但也想调用移动构造函数完成,有没有办法可以实现呢?

默认情况下,左值初始化同类对象只能通过拷贝构造函数完成,如果想调用移动构造函数,则必须使用右值进行初始化。C++11 标准中为了满足用户使用左值初始化同类对象时也通过移动构造函数完成的需求,新引入了 std::move() 函数,它可以将左值强制转换成对应的右值,由此便可以使用移动构造函数。

到此这篇关于C++11中移动构造函数的文章就介绍到这了,更多相关C++11移动构造函数内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++11中移动构造函数案例代码

本文链接: http://www.lsjlt.com/news/176645.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++11中移动构造函数案例代码
    目录1. 拷贝构造函数中的深拷贝问题2. C++移动构造函数(移动语义的具体实现)1. 拷贝构造函数中的深拷贝问题 在 C++ 98/03 标准中,如果想用其它对象初始化一个同类的新...
    99+
    2023-01-04
    C++11移动构造函数 C++11构造函数 C++构造函数
  • C++11移动构造函数的使用
    目录一、引言二、左值和右值三、深拷贝构造函数四、右值引用五、移动构造函数六、std::move()七、参考资料一、引言 移动构造函数是什么?先举个例子,你有一本书,你不想看,但我很想...
    99+
    2024-04-02
  • C++11怎么移动构造函数通常
    这篇文章主要讲解了“C++11怎么移动构造函数通常”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++11怎么移动构造函数通常”吧!不会抛出异常的移动构造函数拷贝构造函数通常伴随着内存分配操...
    99+
    2023-06-19
  • C++赋值函数+移动赋值函数+移动构造函数详解
    目录左值引用和右值引用左值与右值左右值的切换左值引用:将左值绑定在引用上常量左值引用和非常量左值引用右值引用:将右值绑定在引用上常量右值引用和非常量右值引用移动构造函数赋值和移动赋值...
    99+
    2024-04-02
  • C++移动构造函数和移动赋值的用法
    本篇内容介绍了“C++移动构造函数和移动赋值的用法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!移动构造函数首先看通常的拷贝构造函数:拷贝构...
    99+
    2023-06-19
  • C++11继承的构造函数举例分析
    本篇内容主要讲解“C++11继承的构造函数举例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++11继承的构造函数举例分析”吧!假设我们有下面的CRect类:由于今天的内容是讲构造函数的,...
    99+
    2023-06-19
  • C++11中委托构造函数如何使用
    这篇文章将为大家详细讲解有关C++11中委托构造函数如何使用,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。C++11之前的状况构造函数多了以后,几乎必然地会出现代码重复的情况,为了避免这种情...
    99+
    2023-06-19
  • C++11中 constexpr构造函数的作用是什么
    这期内容当中小编将会给大家带来有关C++11中 constexpr构造函数的作用是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。聚合类聚合类(aggregate class)允许利用者直接访问其成员,...
    99+
    2023-06-19
  • C++11继承的构造函数怎么使用
    本篇内容主要讲解“C++11继承的构造函数怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++11继承的构造函数怎么使用”吧!多重继承的情况上述方法在多重继承时仍然有效,除了一种情况:被...
    99+
    2023-06-19
  • 聊聊C++中右值引用和移动构造函数的使用
    目录一: 背景二: 右值引用1. 它到底解决了什么问题2. 右值引用是个什么样子三: 右值引用如何减少对象的创建1. 简要思路2. 一个简单的例子3. 性能优化方案四: 总结一: 背...
    99+
    2024-04-02
  • 如何理解构造函数和构造代码块
    这篇文章主要介绍“如何理解构造函数和构造代码块”,在日常操作中,相信很多人在如何理解构造函数和构造代码块问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解构造函数和构造代...
    99+
    2024-04-02
  • 如何在c++项目中移动构造
    如何在c++项目中移动构造?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。移动构造什么时候该触发移动构造?    &nbs...
    99+
    2023-06-06
  • Java中静态代码块、构造代码块、构造函数和普通代码块的区别
    目录1、静态代码块①、格式②、执行时机③、静态代码块的作用④、静态代码块不能存在任何方法体中⑤、静态代码块不能访问普通变量2、构造代码块①、格式②、执行时机③、构造代码块的作用3、构...
    99+
    2023-05-19
    Java静态代码块 Java代码块区别
  • Java构造函数的相互调用代码示例
    在Java中,当为一个类创建了多个构造函数时,有时想在一个构造函数中调用另一个构造函数以减少代码量。这时可以使用this关键字来实现。有关构造函数的相关内容,大家可以参阅:Java编程中的构造函数详细介绍通常,当使用this关键字时,它意味...
    99+
    2023-05-30
    java 构造函数相互调用 相互
  • C++中构造函数详解
    构造函数按参数为为:有参构造函数和无参构造函数 按类型分为:普通构造函数和拷贝构造函数 构造函数的三种调用方法:括号法,显示法,隐式转换法; //括号法 Person p1; ...
    99+
    2024-04-02
  • C#中怎么构造函数
    本篇内容介绍了“C#中怎么构造函数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!C#构造函数大体上分为静态C#构造函数和实例C#构造函数,实...
    99+
    2023-06-18
  • C#结构体构造函数的实例分析
    这期内容当中小编将会给大家带来有关C#结构体构造函数的实例分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。C#结构体构造函数的应用是如何的呢?C#结构体构造函数的实例1、  &nbs...
    99+
    2023-06-18
  • C++中的构造函数详解
    目录普通变量的初始化构造函数一定会生成默认构造函数吗?防止隐式类型转换赋值与初始化的区别对象的计数成员初始化的顺序类的引用成员构造函数使用注意事项参考总结普通变量的初始化 当我们在定...
    99+
    2024-04-02
  • C++右值引用与移动构造函数基础与应用详解
    目录1.右值引用1.1左值右值的纯右值将亡值右值1.2右值引用和左值引用2.移动构造函数2.1完美的移动转发1.右值引用 右值引用是 C++11 引入的与 Lambda 表达式齐名的...
    99+
    2023-02-13
    C++右值引用 C++移动构造函数
  • C++中怎么静态构造函数
    C++中怎么静态构造函数,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。函数是C++ 语言程序的主要组成部分,一个函数可以调用其他函数。在设计良好的程序中,每个函数都有特定的...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作