前言: C++面向对象的编程过程中,凡是在类中运用到动态内存分配的时候总是会写一个显示的复制构造函数和赋值重载运算符,本文将结合C++ Primer Plus一书的内容分析下原因: 一、在C++编程中如果没有编写下列成员函数...当同时满足以下两个条件的时候就会自动调用复制构造函数: (1)新建一个对象; (2)使用同类中现有对象初始化新对象。 ...而且有些情况编译器会生成临时变量,然后将临时变量在赋值给被传递的对象。 3、默认复制构造函数做了哪些事情? 默认赋值构造函数逐个复制非静态成员的值。注意是值,是一种浅复制。...由于默认复制构造函数中没有num++,而不管用那个构造函数构造出的对象调用的都是同一个析构函数,而析构函数中含有num--,所以临时对象导致num多减了一次,所以最后一句话会出现,“析构后对象的个数是-...当将已有的对象赋给另一个对象时,将使用赋值运算符。 3、默认复制运算符做了什么事情? 其实它和默认的赋值构造函数差不多,都是进行浅复制。
2、为什么会用到原型模式? (1)既然可以直接new,为什么会用到原型模式?...这个可以从两个角度来说,第一,时间消耗角度:如果创建实例的构造函数非常的复杂,在执行这个构造函数时会消耗较长的时间,这时如果需要一个跟刚刚实例化对象参数差不多的实例(可以完全相同,也可以大部分相同)那么直接使用...(2)既然类可以直接赋值,为什么会用到原型模式?...因为类之间直接赋值的话,默认的拷贝函数是进行引用赋值的 对于指针的浅复制会造糟糕的结果,这点可以参见C++ primer plus "类和动态内存分配"章节,也可以参见我的另一篇技术博客 C++类的复制构造函数和赋值运算符...4、所属类别:创建型 二、原型模式的C++程序 1 // 原型模式.cpp : 定义控制台应用程序的入口点。
拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用; C++规定: 内置类型直接拷贝; 自定义类型必须调用拷贝构造函数完成拷贝;...默认的拷贝构造函数和构造函数不同,它是: a.对内置类型完成值拷贝,也就是浅拷贝; b.对自定义类型会去调用它的拷贝构造函数; 但是当有动态资源时,虽然也是内置类型,但也要自己写拷贝构造函数...我们发现自动生成的拷贝构造函数,让两个不同的对象中的 _arr 的地址相同,这样只要其中一个对象的 _arr 改变,另一个对象里的 _arr 也会改变,这并不是我们想要的结果,而且同一个地址还会被析构两次...,那么会自动生成的赋值运算符重载,这和拷贝构造函数类似: 1.对内置类型完成浅拷贝; 2.对自定义类型会去调用它的赋值运算符重载函数 下面是日期类的赋值运算符重载: Date& operator...四.区分拷贝构造和赋值运算符重载 1.当我们用一个已经存在对象去初始化另一个对象时,即使写的是 “ = ” ,此时也调用它的拷贝构造函数; 2.已经存在的两个对象之间赋值拷贝,此时是赋值运算符重载;
比如 AddNode ad1(left, right); AddNode ad2(ad1); 假设允许拷贝且没有自己实现拷贝构造函数(默认为浅拷贝),则会有两个指针同时指向一个Node对象,容易发生析构两次的运行时错误...下面看如何禁止拷贝的两种方法: 方法一:将Node 的拷贝构造函数和赋值运算符声明为私有,并不提供实现 //抽象类 class Node { public: Node() { } virtual...需要注意的是,因为声明了Node类的拷贝构造函数,故必须实现一个构造函数,否则没有默认构造函数可用。...同样地,NonCopyable类的拷贝构造函数和赋值运算符为私有,故如 AddNode ad2(ad1); 编译出错。...从输出可以看出,通过NodePtr 智能指针对象包装了裸指针,NodePtr类通过重载-> 和 * 运算符实现如同裸指针一样的操作,如 np->Calc(); 程序中通过智能指针对象的一次拷贝构造和赋值操作之后
比如 AddNode ad1(left, right); AddNode ad2(ad1); 假设允许拷贝且没有自己实现拷贝构造函数(默认为浅拷贝),则会有两个指针同时指向一个Node对象,容易发生析构两次的运行时错误...下面看如何禁止拷贝的两种方法: 方法一:将Node 的拷贝构造函数和赋值运算符声明为私有,并不提供实现 //抽象类 class Node { public: Node() { } virtual...需要注意的是,因为声明了Node类的拷贝构造函数,故必须实现一个构造函数,否则没有默认构造函数可用。...同样地,NonCopyable类的拷贝构造函数和赋值运算符为私有,故如 AddNode ad2(ad1); 编译出错。...* 运算符实现如同裸指针一样的操作,如 np->Calc(); 程序中通过智能指针对象的一次拷贝构造和赋值操作之后,现在共有3个局部智能指针对象,但np 和 np2 的成员ptr_ 已经被设置为0;第二次
上面说到c++的新的特性学习,但是在嵌入式领域,c++还不会用太新的版本,但是作为自身学习的话,新的东西,还是要去探索学习的,紧跟技术发展,为此我发现这两个学习c++的网站不错,一个是cplusplus...分析:上述代码中分别利用拷贝构造(ap1 => ap2)和 赋值构造(ap3 => ap4)来创建新的 std::auto_ptr 对象,因此 ap1 持有的堆对象被转移给 ap2,ap3 持有的堆对象被转移给....)); } 鉴于 std::auto_ptr 的前车之鉴,std::unique_ptr 禁止复制语义,为了达到这个效果,std::unique_ptr 类的拷贝构造函数和赋值运算符(operator...//拷贝构造函数和赋值运算符被标记为delete unique_ptr(const unique_ptr &) = delete; unique_ptr &operator=(const...并不是所有的对象的 std::move 操作都有意义,只有实现了移动构造函数或移动赋值运算符的类才行,而 std::unique_ptr 正好实现了这二者,以下是实现伪码: template <typename
由于对象成员变量的初始化动作发生在进入构造函数之前,对于内置类型没什么影响,但如果有些成员是类,那么在进入构造函数之前,会先调用一次默认构造函数,进入构造函数后所做的事其实是一次赋值操作(对象已存在),...在C++中,类和结构是只有一个区别的:类的成员默认是private,而结构是public。 this是类的指针,如果换成结构体,那this就是结构的指针了。...拷贝构造函数是函数,赋值运算符是运算符重载。 拷贝构造函数会生成新的类对象,赋值运算符不能。...拷贝构造函数是直接构造一个新的类对象,所以在初始化对象前不需要检查源对象和新建对象是否相同;赋值运算符需要上述操作并提供两套不同的复制策略,另外赋值运算符中如果原来的对象有内存分配则需要先把内存释放掉。...形参传递是调用拷贝构造函数(调用的被赋值对象的拷贝构造函数),但并不是所有出现"="的地方都是使用赋值运算符,如下: Student s; Student s1 = s; // 调用拷贝构造函数
1.智能指针的由来 C++中,动态内存的管理是通过一对运算符来完成的,new用于申请内存空间,调用对象构造函数初始化对象并返回指向该对象的指针。...我们知道析构函数有这个功能。如果ps有一个析构函数,该析构函数将在ps过期时自动释放它指向的内存。但ps的问题在于,它只是一个常规指针,不是有析构凼数的类对象指针。...要避免这种问题,方法有多种: (1)定义陚值运算符,使之执行深复制。这样两个指针将指向不同的对象,其中的一个对象是另一个对象的副本,缺点是浪费空间,所以智能指针都未采用此方案。...对于特定的对象,只能有一个智能指针可拥有,这样只有拥有对象的智能指针的析构函数会删除该对象。然后让赋值操作转让所有权。...当然,同样的策略也适用于复制构造函数,即auto_ptr vocation(ps)时也需要上面的策略。每种方法都有其用途,但为何要摒弃auto_ptr呢? 下面举个例子来说明。
所以为了避免这种情况的出现,C++提供了智能指针模板类,专门用来自动管理内存。 ---- 智能指针初探 常见的智能指针有auto_ptr、unique_ptr、shared_ptr和weak_ptr。...可以考虑下面几种方案: 定义赋值运算符,使之指向深复制,这样两个指针将指向不同的对象,其中一个对象是另外一个的副本。...对于特定的对象,只能有一个智能指针可以拥有它,这样只有拥有对象的智能指针的构造函数会删除该对象。然后,让赋值操作转让所有权。...很多STL容器中的算法都支持复制和赋值操作,这些操作可以用于shared_ptr,但不能用其他两个。 如果程序不需要使用多个指向同一个对象的指针,则可以使用unique_ptr。...因为它使用了C++11中新增的移动构造函数和右值引用。这部分内容后续更新! 引用&参考:《C++ Primer Plus》
这是它的最大特点,所以他的拷贝构造函数和赋值运算符重载函数都只是声明而不定义,而且为了防止有的人在类外定义,所以将函数声明为private。...: 默认构造函数,生成规则和C++98一样,在用户没有声明自定义的构造函数的时候并且编译期需要的时候生成。...析构函数,生成规则和C++98一样,在C++11中有点不同的是,析构函数默认是noexcept。 拷贝构造函数,用户自定义了移动操作会导致不生成默认的拷贝构造函数,其它和C++98的行为一致。...拷贝赋值操作符,用户自定义了移动操作会导致不生成默认的拷贝赋值操作,其它和C++98的行为一致。 移动构造函数和移动赋值操作符,仅仅在没有用户自定义的拷贝操作,移动操作和析构操作的时候才会生成。...,编译器可以根据调用来决定是调拷贝构造还是移动构函数,所以不变: // copy and swap 始终只有一个对象有管理这块空间的权限 shared_ptr &operator=(shared_ptr
+,那么你一定知道 C++98(第一个C++标准) 和 C++11 是两个非常大的C++标准, 但C++14,特别是C++03则是两个小标准....Template deduction of constructors(构造函数的模板参数推导) 一个函数模板可以通过传递的函数参数进行参数的类型推导,但这条规则对于一个特殊的函数模板却不适用:类模板的构造函数...移除 auto_ptr 和 trigraphs auto_ptr std::auto_ptr 是C++标准中第一个智能指针,他的设计目的是为了正确的管理资源.但是他存在一个很大的缺陷: std::auto_ptr...可以进行复制(和赋值)操作,但内部执行的却是移动(move)操作!...(译注:意为 std::auto_ptr 复制(和赋值)操作会改变源操作数的内部数据,因此其不能进行逻辑独立的复制(和赋值)操作,也是因为这个原因, std::auto_ptr 不能作为标准库容器的元素
; 这是会报错的,那为什么呢,p1和p2不都是指向同一块内存吗 这时候咱们可以看下auto_ptr的拷贝构造函数看看了 auto_ptr(auto_ptr& _Right) noexcept : _Myptr...,全部为空,当你在不知道这个的情况下,你使用vec1里面的智能指针,就全部都是空指针了 既然auto_ptr尽量不用,那scoped_ptr呢 我们先看scoped_ptr的拷贝构造函数和拷贝赋值运算符...,它们使用了C++11中的关键字来禁用了这些函数 这意味着你不能使用拷贝构造函数或拷贝赋值运算符来创建一个 scoped_ptr对象的副本,如果你尝试这样做,编译器将报错 其实scoped_ptr的拷贝构造函数是被声明为...这样p1的所有权转移给p2,p1变为空指针 三四行代码,不涉及构造赋值运算符,只涉及到移动构造函数 这时候肯定会说,那和auto_ptr也一样啊,但unique_ptr p2(std::move...,一个带计数 他们两个都是可以带自定义删除器的 看他们的源码 ~unique_ptr(){ 是一个函数对象的调用 deletor(ptr) }相当于deletor调用了他的小括号运算符重载函数 默认的deletor
; // 非法,lambda无法赋值 auto c = a; // 合法,生成一个副本 闭包类型禁用了赋值操作符,但是没有禁用复制构造函数,所以你仍然可以用一个 lambda 表达式去初始化另外一个...所以,采用默认值捕捉所有变量仍然是不安全的,主要是由于指针变量的复制,实际上还是按引用传值。 lambda 表达式可以赋值给对应类型的函数指针。但是使用函数指针并不是那么方便。...对于 C++ 98,答案是复制构造函数,但是对于 C++ 11,编译器会依据参数是左值还是右值在复制构造函数和转移构造函数间进行选择。...如果是 a=b,这样就会调用复制构造函数来初始化 that(因为 b 是左值),赋值操作符会与新创建的对象交换数据,深度拷贝。...= nullptr; } 这个转移构造函数跟 auto_ptr 中复制构造函数做的事情一样,但是它却只能接受右值作为参数。
C++ 和 Java 有一处最大的区别在于语义不同。...在执行完 objPtr2 = objPtr1 赋值后,objPtr1 和 objPtr2 两个指针都将指向同一个 Object 对象。...这就会出现问题,因为程序将试图删除同一个对象两次:一次是 objPtr1 过期,另一次是 objPtr2 过期。 要避免这种问题,方法有多种: 定义赋值运算符,使之执行深复制。...对于特定的对象,只能有一个智能指针可拥有,这样只有拥有对象的智能指针的构造函数会删除该对象。然后让赋值操作转让所有权。...很多 STL 算法都支持复制和赋值操作,这些操作可用于 shared_ptr,但不能用于 unique_ptr(编译器发出 warning)和 auto_ptr(行为不确定)。
也可以看出运算符重载解决的问题很多。 上述的Smartptr大致可以分成两个部分: RAII:此Smartptr构造函数和析构函数的设计思想 重载:像指针一样。 RAII是什么?...对*和->运算符进行重载,使auto_ptr对象具有指针一样的行为。 在拷贝构造函数中,用传入对象管理的资源来构造当前对象,并将传入对象管理资源的指针置空。...用C++98的方式将拷贝构造函数和拷贝赋值函数声明为私有,或者用C++11的方式在这两个函数后面加上=delete,防止外部调用。...在调用拷贝构造函数和拷贝赋值函数时,除了需要将对应的资源和引用计数交给当前对象管理之外,还需要将对应的互斥锁也交给当前对象。...为了简化代码逻辑,可以将拷贝构造函数和拷贝赋值函数中引用计数的自增操作提取出来,封装成AddRef函数,将拷贝赋值函数和析构函数中引用计数的自减操作提取出来,封装成ReleaseRef函数,这样就只需要对
std::auto_ptr 真正让人容易误用的地方是其不常用的复制语义,即当复制一个 std::auto_ptr 对象时(拷贝复制或 operator = 复制),原对象所持有的堆内存对象也会转移给复制出来的对象....)); } 鉴于 std::auto_ptr 的前车之鉴,std::unique_ptr 禁止复制语义,为了达到这个效果,std::unique_ptr 类的拷贝构造函数和赋值运算符(operator...//拷贝构造函数和赋值运算符被标记为delete unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const...并不是所有的对象的 std::move 操作都有意义,只有实现了移动构造函数(Move Constructor)或移动赋值运算符(operator =)的类才行,而 std::unique_ptr 正好实现了这二者...,同时触发对象 A 的构造,因此 A 的构造函数会执行; 此时只有一个 sp1 对象引用 22 行 new 出来的 A 对象(为了叙述方便,下文统一称之为资源对象 A),因此代码 24 行打印出来的引用计数值为
要避免这种问题,方法有多种: (1)定义陚值运算符,使之执行深复制。这样两个指针将指向不同的对象,其中的一个对象是另一个对象的副本,缺点是浪费空间,所以智能指针都未采用此方案。...对于特定的对象,只能有一个智能指针可拥有,这样只有拥有对象的智能指针的析构函数会删除该对象。然后让赋值操作转让所有权。...当然,同样的策略也适用于复制构造函数,即auto_ptr vocation(ps)时也需要上面的策略。每种方法都有其用途,但为何要摒弃auto_ptr呢? 下面举个例子来说明。...这样的情况包括: (1.1)有一个指针数组,并使用一些辅助指针来标示特定的元素,如最大的元素和最小的元素; (1.2)两个对象都包含指向第三个对象的指针; (1.3)STL容器包含指针。...很多STL算法都支持复制和赋值操作,这些操作可用于shared_ptr,但不能用于unique_ptr(编译器发出warning)和auto_ptr(行为不确定)。
3.1 隐式转换 C++自定义类型在以下两种情况会发生隐式转换: 1) 类构造函数只有一个参数或除第一个参数外其他参数有默认值; 2) 类实现了operator type()函数;...) { Person::~Person(); throw; }} 表面上构造函数定义为空且是inline,但编译器实际会生成如右侧的伪代码来构造基类成分和成员变量...5 名称查找 C++中名称主要分为以下几类: a) 受限型名称:使用作用域运算符(::)或成员访问运算符(.和->)修饰的名称。...在分布式事务领域有二阶段提交,在并发编程设计模式中二阶段终止模式。在C++名称查找中也存在一个二阶段查找。...this指针构造了两个没有关系的shared_ptr,在离开作用域时导致重复析构问题,和1)是一个道理。
union 联合 联合(union)是一种节省空间的特殊的类,一个 union 可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。当某个成员被赋值后其他成员变为未定义状态。...修饰构造函数时,可以防止隐式转换和复制初始化 explicit 修饰转换函数时,可以防止隐式转换,但 按语境转换 除外 explicit 使用 struct A { A(int) { } operator...右值引用可实现转移语义(Move Sementics)和精确传递(Perfect Forwarding),它的主要目的有两个方面: 消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。...unique_ptr 用于取代 auto_ptr auto_ptr 被 c++11 弃用,原因是缺乏语言特性如 “针对构造和赋值” 的 std::move 语义,以及其他瑕疵。...auto_ptr 与 unique_ptr 比较 auto_ptr 可以赋值拷贝,复制拷贝后所有权转移;unqiue_ptr 无拷贝赋值语义,但实现了move 语义; auto_ptr 对象不能管理数组
领取专属 10元无门槛券
手把手带您无忧上云