详解C++-(=)赋值操作符、智能指针编写

(=)赋值操作符

  • 编译器为每个类默认重载了(=)赋值操作符
  • 默认的(=)赋值操作符仅完成浅拷贝
  • 默认的赋值操作符和默认的拷贝构造函数有相同的存在意义

(=)赋值操作符注意事项

首先要判断两个操作数是否相等

返回值一定是 return *this; 返回类型是Type&型,避免连续使用=后,出现bug

比如:

class Test{
    int *p;
    Test(int i)
    {
       p=new int(i);
    }
    Test& operator = (const Test& obj)
    {
       if(this!=obj)
       {
           delete p;
           p=new int(*obj.p);
       }
       return *this;
    }
};

编译器默认提供的类函数

包括了:构造函数,析构函数,拷贝构造函数, (=)赋值操作符

智能指针

智能指针的由来

在以前C程序里,使用malloc()等函数动态申请堆空间时,若不再需要的内存没有被及时释放,则会出现内存泄漏,若内存泄漏太多,

则会直接导致设备停止运行,特别是嵌入式设备,可能有些设备一上电就要运行好几个月.

在C++里,为了减少内存泄漏,所以便引出了智能指针

介绍

  • 智能指针实际上是将指针封装在一个类里,通过对象来管理指针.
  • 在构造函数时,通过对象将指针传递进来,指针可以是缺省值.
  • 然后构造“ -> ” “ * ” “ = ”等操作符重载,让这个对象拥有指针的特性.
  • 最后通过析构函数,来释放类里的指针.

注意

  • 智能指针只能指向堆空间中的对象或者变量
  • 并且一片空间最多只能由一个智能指针标识(因为多个指向地址相同的智能指针调用析构函数时,会出现bug)
  • ->和*都是一元操作符,也就是说不能带参数

比如ptr->value的->:

当ptr的类型是普通指针类型时,等价于:(*ptr).mem

当ptr的类型是类时,等价于:(ptr.operator->())->value    等价于: ( *(ptr.operator->()) ).value

所以->操作符函数的返回类型是type*,返回值是一个指针变量本身(不带*)

接下来个示例,指向一个int型的智能指针

#include <iostream>
using namespace std;
class Point{
    int *p;
public:
    Point(int *p=NULL)
    {
     this->p = p;
    }
    int* operator -> ()
    {
       return p;
    }
    int& operator *()
    {
       return *p;
    }
    ~Point()
    {
     cout<<"~Point()"<<endl;
     delete p;
    }
};
int main()
{
    for(int i=0;i<5;i++)
    {
    Point p=new int(i);
    cout <<*p<<endl;
    }
    return 0;
}

运行打印:

0
~Point()
1
~Point()
2
~Point()
3
~Point()
~Point()

从结果可以看到, Point p每被从新定义之前,便会自动调用析构函数来释放之前用过的内存,这样便避免了野指针的出现。

接下来,我们继续完善上面代码,使它能够被赋值.

#include <iostream>
using namespace std;
class Point{
    int *p;
public:
    Point(int *p=NULL)
    {
     this->p = p;
    }
    bool isNULL()
    {
       return (p==NULL);
    }
    int* operator -> ()
    {
       return p;
    }
    int& operator *()
    {
       return *p;
    }
   Point& operator = (const Point& t)
    {
       cout<<"operator =()"<<endl;
       if(this!=&t)
       {
           delete p;
           p = t.p;
           const_cast<Point&>(t).p=NULL;
       }
       return *this;
    }
    ~Point()
    {
     cout<<"~Point()"<<endl;
     delete p;
    }
};
int main()
{
    Point p=new int(2);
    Point p2;
    p2= p;     //等价于 p2.operator= (p);
    cout <<"p=NULL:"<<p.isNULL()<<endl;
    *p2+=3;    //等价于 *(p2.operator *())=*(p2.operator *())+3;
             //p2.operator *()返回一个int指针,并不会调用Point类的=操作符
    cout <<"*p2="<<*p2 <<endl;
    return 0;
}

运行打印:

operator =()      
p=NULL:1              // Point  p的成员已被释放
*p2=5
~Point()
~Point()

但是,还有个缺点,就是这个智能指针仅仅只能指向int类型,没办法指向其它类型.

总结

以上所述是小编给大家介绍的C++-(=)赋值操作符、智能指针编写,希望对大家有所帮助,如果大家有任何疑问请给我留

言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • C++中复制构造函数和重载赋值操作符总结

    前言 这篇文章将对C++中复制构造函数和重载赋值操作符进行总结,包括以下内容: 1.复制构造函数和重载赋值操作符的定义: 2.复制构造函数和重载赋值操作符的调用时机: 3.复制构造函数和重载赋值操作符的实现要点: 4.复制构造函数的一些细节. 复制构造函数和重载赋值操作符的定义 我们都知道,在C++中建立一个类,这个类中肯定会包括构造函数.析构函数.复制构造函数和重载赋值操作:即使在你没有明确定义的情况下,编译器也会给你生成这样的四个函数.例如以下类: 复制代码 代码如下: class CTes

  • C++中智能指针如何设计和使用

    智能指针(smart pointer)是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露.它的一种通用实现技术是使用引用计数(reference count).智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针.每次创建类的新对象时,初始化指针并将引用计数置为1:当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数:对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果

  • C++智能指针实例详解

    本文通过实例详细阐述了C++关于智能指针的概念及用法,有助于读者加深对智能指针的理解.详情如下: 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 delete 的情况并不罕见. 用智能指针便可以有效缓解这类问题,本文主要讲解参见的智能指针的用法.包括:std::auto_ptr.boost::scoped_ptr.boost::shared_p

  • C++11新特性之智能指针(shared_ptr/unique_ptr/weak_ptr)

    shared_ptr基本用法 shared_ptr采用引用计数的方式管理所指向的对象.当有一个新的shared_ptr指向同一个对象时(复制shared_ptr等),引用计数加1.当shared_ptr离开作用域时,引用计数减1.当引用计数为0时,释放所管理的内存. 这样做的好处在于解放了程序员手动释放内存的压力.之前,为了处理程序中的异常情况,往往需要将指针手动封装到类中,通过析构函数来释放动态分配的内存:现在这一过程就可以交给shared_ptr去做了. 一般我们使用make_shared来

  • 详解C++中赋值和输入输出语句的用法

    C++赋值语句讲解 C++的赋值语句具有其他高级语言的赋值语句的功能.但不同的是,C++中的赋值号"="是一个运算符,可以写成 a=b=c=d; 而在其他大多数语言中赋值号不是运算符,上面的写法是不合法的. 关于赋值表达式与赋值语句的概念.在C++中,赋值表达式可以包括在其他表达式之中,例如: if((a=b)>0) cout<<"a>0"<<endl; 按语法规定if后面的( )内是一个条件.现在在x的位置上换上一个赋值表达式&

  • C++中对象的赋值与复制操作详细解析

    对象的赋值 如果对一个类定义了两个或多个对象,则这些同类的对象之间可以互相赋值,或者说,一个对象的值可以赋给另一个同类的对象.这里所指的对象的值是指对象中所有数据成员的值. 对象之间的赋值也是通过赋值运算符"="进行的.本来赋值运算符"="只能用来对单个的变量赋值,现在被扩展为两个同类对象之间的赋值,这是通过对赋值运算符的重载实现的. 实际上这个过程是通过成员复制来实现的,即将一个对象的成员值一一复制给另外一个对象的成员.对象赋值的一般形式: 对象名1=对象名2;

  • C++中赋值运算符与逗号运算符的用法详解

    赋值运算符 赋值符号"="就是赋值运算符,它的作用是将一个数据赋给一个变量.如"a=3"的作用是执行一次赋值操作(或称赋值运算).把常量3赋给变量a.也可以将一个表达式的值赋给一个变量. 赋值过程中的类型转换 如果赋值运算符两侧的类型不一致,但都是数值型或字符型时,在赋值时会自动进行类型转换. 1)  将浮点型数据(包括单.双精度)赋给整型变量时,舍弃其小数部分. 2)  将整型数据赋给浮点型变量时,数值不变,但以指数形式存储到变量中. 3) 将一个double型数

  • 浅析Boost智能指针:scoped_ptr shared_ptr weak_ptr

    一. scoped_ptrboost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放.下列代码演示了该指针的基本应用: 复制代码 代码如下: #include <string>#include <iostream>#include <boost/scoped_ptr.hpp> class implementation{public:    ~implementation() { std::cout

  • C++ 智能指针深入解析

    1. 为什么需要智能指针?简单的说,智能指针是为了实现类似于Java中的垃圾回收机制.Java的垃圾回收机制使程序员从繁杂的内存管理任务中彻底的解脱出来,在申请使用一块内存区域之后,无需去关注应该何时何地释放内存,Java将会自动帮助回收.但是出于效率和其他原因(可能C++设计者不屑于这种傻瓜氏的编程方式),C++本身并没有这样的功能,其繁杂且易出错的内存管理也一直为广大程序员所诟病. 更进一步地说,智能指针的出现是为了满足管理类中指针成员的需要.包含指针成员的类需要特别注意复制控制和赋值操作,

  • 详解C++-(=)赋值操作符、智能指针编写

    (=)赋值操作符 编译器为每个类默认重载了(=)赋值操作符 默认的(=)赋值操作符仅完成浅拷贝 默认的赋值操作符和默认的拷贝构造函数有相同的存在意义 (=)赋值操作符注意事项 首先要判断两个操作数是否相等 返回值一定是 return *this; 返回类型是Type&型,避免连续使用=后,出现bug 比如: class Test{ int *p; Test(int i) { p=new int(i); } Test& operator = (const Test& obj) { i

  • 详解C++赋值操作符重载

    1.赋值操作符重载的原因 赋值操作符是一个使用频率最高的操作之一,通常情况下它的意义十分明确,就是将两个同类型的变量的值从一端(右端)传到另一端(左端).但在以下两种情况下,需要对赋值操作符进行重载. 一是赋值号两边的表达式类型不一样,且无法进行类型转换. 二是需要进行深拷贝. 2. 赋值操作符重载的注意事项 赋值操作符只能通过类的成员函数的形式重载.这就说明了,如果要将用户自定义类型的值传递给基本数据类型的变量,只能通过类型转换机制,而不能利用重载来实现. 当赋值号两边的表达式不一致的时候,可

  • 详解C语言中二级指针与链表的应用

    目录 前言 二级指针讲解 链表的应用 定义双链表的结构体 创建双链表 前言 这篇文章即将解决你看不懂或者不会写链表的基本操作的问题,对于初学者而言,有很多地方肯定是费解的.比如函数的参数列表的多样化,动态分配内存空间函数malloc等,其实这些知识和指针联系紧密,尤其是二级指针.那么开始好好的学习这篇文章吧! 二级指针讲解 简述:其实就是一个指针指向另一个指针的地址. 我们都知道指针指向地址,但是指针自身也是一个变量,当然也可以被二级指针所指向. 语法:形如 int x = 10; int *q

  • 详解pandas赋值失败问题解决

    一.pandas对整列赋值 这个比较正常,一般直接赋值就可以: x = pd.DataFrame({'A': ['1', '2', '3', None, None], 'B': ['4', '5', '6', '7', None]}) x['A'] = ['10', '11', '12', '13', '14'] 二.pandas对非整列赋值 1.用单个值赋值 x = pd.DataFrame({'A': ['1', '2', '3', None, None], 'B': ['4', '5',

  • C++详解PIMPL指向实现的指针

    目录 二进制兼容性 功能实现细节隐藏 编译依赖 动态配置功能的实现方法 二进制兼容性 ①.概述 二进制兼容是指当库文件升级后所有使用该库的应用程序不必重新编译,其本质就是类的内存布局不变.使用 pimpl 方法设计类可以实现二进制兼容的目的. ②.类成员更改后的内存布局 原始类定义: class demoClass { private: int a; int b; }; 类更改后的定义: class demoClass { private: char c; int a; int b; }; ②.

  • 详解C++中的this指针与常对象

    C++ this指针详解 this 是C++中的一个关键字,也是一个常量指针,指向当前对象(具体说是当前对象的首地址).通过 this,可以访问当前对象的成员变量和成员函数. 所谓当前对象,就是正在使用的对象,例如对于stu.say();,stu 就是当前对象,系统正在访问 stu 的成员函数 say(). 假设 this 指向 stu 对象,那么下面的语句中,this 就和 pStu 的值相同: Student stu; //通过Student类来创建对象 Student *pStu = &s

  • 详解C++中的对象指针与对象数组

    C++对象指针 指向对象的指针 在建立对象时,编译系统会为每一个对象分配一定的存储空间,以存放其成员.对象空间的起始地址就是对象的指针.可以定义一个指针变量,用来存放对象的指针. 如果有一个类: class Time { public : int hour; int minute; int sec; void get_time( ); }; void Time::get_time( ) { cout<<hour<<":"<<minute<<

  • 详解C语言中的指针与数组的定义与使用

    指针的特点 他就是内存中的一个地址 指针本身运算 指针所指向的内容是可以操作的 操作系统是如何管理内存的 栈空间 4M~8m的大小 当进入函数的时候会进行压栈数据 堆空间 4g的大小 1g是操作系统 全局变量 内存映射 可以对内存的内容修改修改硬盘的内容 一般在数据库中经常使用 内存的分配与释放 c语言分配内存的方法 // malloc(需要分配的大小): 这里的分配的大小需要对齐的2的指数 void *mem = malloc(size); 释放内存 // 一般分配的内容都是在堆空间中的 //

  • GO语言的控制语句详解包括GO语言的指针语法

    GO语言的控制语句 判断结构:if-else 和大多数编程语言一样,if-else的用法基本都一样,直接来一个GO语言的例子 package main import ( "fmt" ) func main( var str string = "A" if str=="A"{ fmt.Println("匹配成功") }else{ fmt.Println("匹配失败") } ) 输出为:匹配成功如果更改了str

  • 详解php比较操作符的安全问题

    php的比较操作符有==(等于)松散比较,===(完全等于)严格比较,这里面就会引入很多有意思的问题. 在松散比较的时候,php会将他们的类型统一,比如说字符到数字,非bool类型转换成bool类型,为了避免意想不到的运行效果,应该使用严格比较.如下是php manual上的比较运算符表: 例子 名称 结果 $a == $b 等于 TRUE,如果类型转换后 $a 等于 $b. $a === $b 全等 TRUE,如果 $a 等于 $b,并且它们的类型也相同. $a != $b 不等 TRUE,如

随机推荐