C++学习总结(三)

包括以下内容:

智能指针

auto_ptr定义在memory头文件中,接受一个类型参数的模板,为动态分配的对象提供异常安全。

  • auto_ptr不能管理动态分配的数组,所以不能将auto_ptr存储在标准库容器类型中;

  • auto_ptr对象超出作用域或者另外撤销的时候,就自动回收auto_ptr所指向的动态分配对象;

  • auto_ptr可以在newdelete之间发生异常时回收内存;

  • auto_ptr可以保持任何类型;

  • 不能直接将一个地址赋值给auto_ptr对象;

  • 接受指针的构造函数为explicit构造函数。

初始化:

因为构造函数为explicit,所以必须使用初始化的直接形式来创建auto_ptr对象:

auto_ptr<int> pi = new int(1024);//错误,无法自动完成int到auto_ptr的转换
auto_ptr<int> pi(new int(1024));//正确,直接用new初始化

复制和赋值:

auto_ptr的复制和赋值改变右操作数,即在复制或赋值时把基础对象的所有权从原来的auto_ptr对象转给副本,原来的auto_ptr对象重置为未绑定

赋值会删除左操作数指向的对象,例:

auto_ptr<int> ap1(new int(1));
auto_ptr<int> ap2(new int(2));
ap1 = ap2;

ap2赋值给ap1后:

  • 删除了ap1所指向的对象;

  • ap1置为指向ap2所指的对象;

  • ap2是未绑定的auto_ptr对象。

测试auto_ptr对象:

如果不给定初始值,auto_ptr对象是未绑定的,默认情况下,auto_ptr的内部指针值为0

为了检查auto_ptr是否绑定,不能直接测试,要用get成员.

auto_ptr<int> ptr;  //未绑定
if(ptr.get())   //用get来判断,未绑定返回0
    *ptr = 2;
else
    ptr.reset(new int (3)); //只能用reset重设
    //要复位auto_ptr对象可以将0传给reset函数

缺陷:

要正确使用auto_ptr类,必须坚持该类强加的下列限制:

  1. 不要使用auto_ptr对象保存指向静态分配对象的指针,否则,当auto_ptr对象本身被销毁的时候,它将试图删除指向非动态分配对象的指针,导致未定义的行为;

  2. 不要使用两个auto_ptr对象指向同一对象,不要使用同一指针来初始化或者reset两个不同的auto_ptr对象,不要使用一个auto_ptr对象的get函数的结果来初始化或者reset另一个auto_ptr对象。

  3. 不要使用auto_ptr对象保存指向动态分配数组的指针,因为auto_ptr对象被删除时调用的是普通delete操作符,而不是数组的delete[]操作符;

  4. 不要讲auto_ptr对象存储在容器中。

has-a设计与is-a设计

has-a:基于用法(即引用)而不是继承,表示组合,包含关系。一个对象包含另一个对象

is-a:基于类继承或接口实现,示的是属于关系。具体类是接口的一种实现。

is-a是继承,has-a是组合

auto关键字

作用: C++ 11中引入的auto主要有两种用途:自动类型推断返回值占位

auto声明的变量必须被初始化,以使编译器能够从其初始化表达式中推导出其类型。这个意义上,auto并非一种类型声明,而是一个类型声明时的占位符

auto推导的一个最大的优势在于拥有初始化表达式的复杂类型变量声明时简化代码

可以避免类型声明时的麻烦而且避免类型声明时的错误

auto与模板一起使用时,其“自适应”特性能够加强C++中泛型的能力

Tips:

  • auto声明的变量必须初始化;

  • auto不能与其他类型组合连用;

  • 函数和模板参数不能被声明为auto

  • auto是一个占位符,并不是一个他自己的类型,因此不能用于类型转换或其他一些操作;

  • auto会退化成指向数组的指针,除非被声明为引用。

    int a[9];  
    auto j = a;  
    cout << typeid(j).name() << endl; // This will print int*  
    auto& k = a;  
    cout << typeid(k).name() << endl; // This will print int [9]  

auto返回值占位,主要与decltype配合使用,用于返回值类型后置时的占位。

template <class T, class U>
    auto Multiply(T t, U u)->decltype(t*u)
{
    typedef decltype(t*u) NewType;
    NewType *pResult =  NewType(t*u);
    return *pResult;
}

至于为什么需要将返回值类型后置,这里简单说明一下。如果没有后置,则函数声明为decltype(t*u) Multiply(T t, U u),但此时模板参数t和u还未声明,编译无法通
过。另外,如果非要使用返回值类型前置的形式,也可以将函数声明为decltype((*(T *)0)*(*(U *)0)) Multiply(T t, U u),但这种形式比较晦涩难懂,因此不推荐采用。

参考:

http://www.cnblogs.com/hujian/archive/2012/02/15/2352050.html

volatile关键字

volatile的本意是易变的volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。

遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

当要求使用volatile声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被寄存。

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:

  1. 并行设备的硬件寄存器(如:状态寄存器

  2. 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

  3. 多线程应用中被几个任务共享的变量


问题:

  • 一个参数既可以是const还可以是volatile吗?解释为什么。
    是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。

  • 一个指针可以是volatile吗?解释为什么。
    是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。

  • 下面的函数有什么错误?

    int square(volatile int *ptr)
    {
        return *ptr * *ptr;
    }

    这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:

    int square(volatile int *ptr)
    {
        int a,b;
        a = *ptr;
        b = *ptr;
        return a * b;
    }

    由于*ptr的值可能被意想不到地该变,因此ab可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:

    long square(volatile int *ptr)
    {
        int a;
        a = *ptr;
        return a * a;
    }

参考:

C++中const、volatile、mutable的用法

mutable关键字

mutalbe的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。

C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量(mutable只能由于修饰类的非静态数据成员),将永远处于可变的状态,即使在一个const函数中。

假如类的成员函数不会改变对象的状态,那么这个成员函数一般会声明为const。但是,有些时候,我们需要在const的函数里面修改一些跟类状态无关的数据成员,那么这个数据成员就应该被mutalbe来修饰。

参考:

C++基本功: 全面掌握const, volatile 和 mutable关键字


本文来自我的独立博客,欢迎访问。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值