zoukankan      html  css  js  c++  java
  • EC笔记:第3部分:15、对原始资源的访问

        使用对象来管理资源,可以避免因个人疏忽带来的一些低级错误,但是不是每件事都是称心如意的。

        一些函数依然使用原始的资源对象,那么我们就需要为这些函数提供一个接口,让他们可以获取到原始对象。

        继续拿13节的智能指针说事,先上代码:

    //SFAutoPtr.h

    #pragma once

    template<typename T>

    class SFAutoPtr {

    private:

    T* pointer; //对象指针

    size_t *ref_count; //引用计数

    void dec() { //减少引用计数

    if(*ref_count == 0) { //如果当前引用计数为0,则应该释放资源

    delete pointer;

    pointer = nullptr;

    delete ref_count;

    ref_count = nullptr;

    return;

    }

    --*ref_count;

    }

    void inc() { //增加引用计数

    ++*ref_count;

    }

    public:

    SFAutoPtr() : //默认构造函数,生成一个指针

    pointer(new T),

    ref_count(new size_t(0)) {}

     

    template<typename ... Init_Type>

    SFAutoPtr(Init_Type...args) : //带参数的构造函数,对象带有指针

    pointer(new T(args...)),

    ref_count(new size_t(0)) {}

     

    SFAutoPtr(const SFAutoPtr<T>& other) { //拷贝构造函数,增加引用计数

    pointer = other.pointer;

    ref_count = other.ref_count;

    inc();

    }

     

    bool operator==(const SFAutoPtr<T>& other) const{ //等于操作符,判断指针是否相等,这时候不应该比较ref_count

    return pointer == other.pointer;

    }

     

    const SFAutoPtr<T>& operator=(const SFAutoPtr<T>& other) { //赋值运算符,需要将当前引用计数-1,赋值的引用计数+1

    if(this == &other)

    return *this;

    dec();

    pointer = other.pointer;

    ref_count = other.ref_count;

    inc();

    return *this;

    }

     

    T operator*(int) { //解引用运算符

    return *pointer;

    }

     

    operator T*() { //指针运算符,适用于使用指针作为参数的函数

    return pointer;

    }

     

    T* operator->() { //成员访问操作符

    return pointer;

    }

     

    ~SFAutoPtr() { //析构函数,需要将引用计数-1

    dec();

    }

    };

     

    注意其中的:

    operator T*() { //指针运算符,适用于使用指针作为参数的函数

    return pointer;

    }

    这里就是为需要T*类型作为参数的函数提供接口,如下:

    #include <iostream>

    using namespace std;

     

    void func(int *){

        cout<<"hello world"<<endl;

    }

     

    int main(){

        SFAutoPtr<int> t;

        func(t);

    }

     

    SFAutoPtr<int>能够很好地适应int*类型的参数,这为编码提供了不少方便,但是随之也带来了一些安全隐患:

    例如,有人可能写出下面这样的代码(没错,就是小明!!!):

    #include <iostream>

    using namespace std;

     

    int *p;

     

    void setP(){

        p=SFAutoPtr<int>(5);

    }

     

    int main(){

        setP();

        cout<<*p<<endl;

    }

     

    这里不会输出5,而是会输出一个随机值,甚至程序崩溃,因为我们使用了对象管理资源,对象在销毁时,资源也会被释放。导致这一现象的原因是AFAutoPtr<int>被隐式转换为了int*,避免这种调用的方法之一就是,不再提供隐式转换,确保编写出的每一个转换都是程序员想要的,使用get()而非operator T*,将原实现中的operator T*操作符替换为get()函数。有人可能要问,如果程序员非得写出:

    #include <iostream>

    using namespace std;

     

    int *p;

     

    void setP(){

        SFAutoPtr<int> tmp(5);

        p=tmp.get();

    }

     

    int main(){

        setP();

        cout<<*p<<endl;

    }

    这样的代码怎么办?

    对此我只能说:自作孽,不可活~~~

     

    一般使用对象管理资源,都会提供接口访问原始对象。是使用隐式访问还是显式访问,这主要看实际需求,是为程序员带来便捷还是给程序员带来安全,你说了算~~~

  • 相关阅读:
    css3 3d 转换
    css3 动画序列
    css3 动画
    2d 转换之缩放
    2d 转换中心点
    css3 书写 动画三角形
    2d 旋转
    2D转换
    伪元素 字体图标
    风陵01
  • 原文地址:https://www.cnblogs.com/SkyFireITDIY/p/6216404.html
Copyright © 2011-2022 走看看