C++day09 类域(全局作用域、类作用域、块作用域)和深拷贝、写时复制、短字符串优化、第三方库优化短字符

本文详细介绍了C++中的全局作用域、类作用域、块作用域及其应用,包括内部类、Pimpl设计模式以及单例模式的四种实现方式。此外,还探讨了std::string的底层实现,包括深拷贝、浅拷贝和短字符串优化。文章通过实例代码展示了作用域的使用和单例模式的自动释放,帮助读者深入理解C++的类域和设计模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.总体目录框架

在这里插入图片描述
在这里插入图片描述

2.类域

(1)全局作用域

在函数和其他类定义的外部定义的类称为全局类,绝大多数的 C++ 类是定义在该作用域中,我们在前面定义的所有类都是在全局作用域中,全局类具有全局作用域

(2)类作用域

一个类可以定义在另一类的定义中,这是所谓嵌套类或者内部类
①如果A的访问权限是public,则A的作用域可认为和B的作用域相同
②如果A的访问权限是private,则只能在类内使用类名创建该类的对象,无法在外部创建A类的对象
内部类(嵌套类)
1)应用 pimpl :PIMPL(Private Implementation 或Pointer to >Implementation)是通过一个私有的成员指针,将指针所指向的类的内部实现数据进>行隐藏
设计模式有如下优点:
1.提高编译速度;
2. 实现信息隐藏;
3. 减小编译依赖,可以用最小的代价平滑的升级库文件;
4. 接口与实现进行解耦;
5. 移动语义友好。

2)单例模式的自动释放 四种方式
①友元形式
②嵌套类 + 静态对象(饱汉(懒汉)模式)
③atexit方式进行(饿汉模式)
④atexit+pthread_once形式,平台相关(多线程安全,用到pthread_once()
3)内存泄漏的检测工具:valgrind
使用方法:
valgrind --tool=memcheck --leak-check=full ./执行文件

(3)块作用域

例如可以存在在test()函数块中,很少见

(4)具体代码

作用域与可见域:如果没有同名的话,变量的作用域与可见域是一样的。
1)补充作用域总结打印
2)补充类作用域(内部类)
3)设计模式之Pimpl实现
4)单例模式的自动释放 四种方式
①友元形式
②嵌套类 + 静态对象(饱汉(懒汉)模式)
③atexit方式进行(饿汉模式)
④atexit+pthread_once形式,平台相关(多线程安全)

1)补充作用域总结打印

#include <iostream>
using std::cout;
using std::endl;

int x = 1;

namespace wd
{
int x = 10;

class Test
{
public:
    Test(int value)
    : x(value)
    {

    }

    void print(int x) const
    {
        cout << "形参x = " << x << endl; //300
        cout << "数据成员x = " << this->x << endl;  //400
        cout << "数据成员x = " << Test::x << endl;  //400
        cout << "命名空间中的x = " << wd::x << endl; //10
        cout << "全局的x = " << ::x << endl;        //1
    }
private:
    int x;
};
}//end of namespace wd
int main(int argc, char **argv)
{
    int value = 300;
    wd::Test tst(400);
    tst.print(value);

    return 0;
}

2)补充类作用域(内部类)

#include <iostream>

using std::cout;
using std::endl;


class Line
{
public:
    Line(int x1, int y1, int x2, int y2)
    : _pt1(x1, y1)//类对象成员需要显示进行初始化,否则就是默认值
    , _pt2(x2, y2)
    {
        cout << "Line(int, int, int,int)" << endl;
    }

    void printLine()
    {
        _pt1.print();
        _pt2.print();
    }

    ~Line()
    {
        cout << "~Line()" << endl;
    }
private:
    class Point
    {
    public:
        Point(int ix = 0, int iy = 0)
        : _ix(ix)
        , _iy(iy)
        {
            cout << "Point(int = 0, int = 0)" << endl;
        }
    
        void print()
        {
            cout << "(" << _ix << ", "
                  << _iy << ")" <<  endl;
        }
    
        ~Point()
        {
            cout << "~Point()" << endl;
        }
    private:
        int _ix;
        int _iy;
    };

private:
    Point _pt1;//类对象成员(子对象)
    Point _pt2;
};
int main(int argc, char **argv)
{
    Line line(1, 2, 3, 4);
    line.printLine();

    //要想直接使用Point类的话,外面不能直接访问,下面是错误的
    /* Line::Point pt1(1, 3);//error */
    return 0;
}

3)设计模式之Pimpl实现
①头文件:point.h
②构建Line类的实现 point.cc
③测试 testpoint.cc

//point.h
#ifndef __POINT_H__
#define __POINT_H__

class Line
{
public:
    Line(int x1, int y1, int x2, int y2);
    void printLine();
    ~Line();
    class PointPimpl;
private:
    PointPimpl *_pimpl;
};
#endif
//point.cc
#include "Point.h"
#include <iostream>

using std::cout;
using std::endl;


class Line::PointPimpl
{
public:
    PointPimpl(int x1, int y1, int x2, int y2)
    : _pt1(x1, y1)//类对象成员需要显示进行初始化,否则就是默认值
    , _pt2(x2, y2)
    {
        cout << "PointPimpl(int, int, int,int)" << endl;
    }

    void printPimpl()
    {
        _pt1.print();
        _pt2.print();
    }

    ~PointPimpl()
    {
        cout << "~PointPimpl()" << endl;
    }
private:
    class Point
    {
    public:
        Point(int ix = 0, int iy = 0)
        : _ix(ix)
        , _iy(iy)
        {
            cout << "Point(int = 0, int = 0)" << endl;
        }
    
        void print()
        {
            cout << "(" << _ix << ", "
                  << _iy << ")" <<  endl;
        }
    
        ~Point()
        {
            cout << "~Point()" << endl;
        }
    private:
        int _ix;
        int _iy;
    };

private:
    Point _pt1;//类对象成员(子对象)
    Point _pt2;
};

Line::Line(int x1, int y1, int x2, int y2)
: _pimpl(new PointPimpl(x1, y1, x2, y2))
{
    cout << "Line(int, int, int, int)" << endl;
}

void Line::printLine()
{
    _pimpl->printPimpl();
}

Line::~Line()
{
    cout << "~Line()" << endl;
    if(_pimpl)
    {
        delete _pimpl;
        _pimpl  = nullptr;
    }
}
#include "Point.h"
#include <iostream>

using std::cout;
using std::endl;

int main(int argc, char **argv)
{
    Line line(1, 2, 3, 4);
    line.printLine();
    return 0;
}

4)四种单例类模式
①友元形式
②嵌套类 + 静态对象(饱汉(懒汉)模式)
③atexit方式进行(饿汉模式)
④atexit+pthread_once形式,平台相关(多线程安全)

//①友元形式实现单例类
#include <iostream>

using std::cout;
using std::endl;

//1、使用友元
class AutoRelease;//类的前向声明

class Singleton
{
    friend class AutoRelease;
public:
//类中的static变量会保证全局唯一,多个实例共享一个static变量,如果该static变量已经初始化过了,不会再次初始化!
    static Singleton *getInstance()
    {
        if(nullptr == _pInstance)
        {
            _pInstance = new Singleton();
        }

        return _pInstance;
    }

    static void destroy()
    {
        if(_pInstance)
        {
            delete _pInstance;
            _pInstance = nullptr;
        }
    }
private:
    Singleton()
    {
        cout << "Singleton()" << endl;
    }

    ~Singleton()
    {
        cout << "~Singleton()" << endl;
    }
private:
    static Singleton *_pInstance;
};

Singleton *Singleton::_pInstance = nullptr;

class AutoRelease
{
public:
    AutoRelease()
    {
        cout << "AutoRelease()" << endl;
    }

    ~AutoRelease()
    {
        cout << "~AutoRelease()" << endl;
        if(Singleton::_pInstance)
        {
            delete Singleton::_pInstance;
            Singleton::_pInstance = nullptr;
        }
    }
};
int main(int argc, char **argv)
{
    Singleton *ps1 = Singleton::getInstance();
    AutoRelease ar;//栈对象

    /* Singleton::destroy(); */
    return 0;
}
//②嵌套类 + 静态对象(饱汉(懒汉)模式)
#include <iostream>

using std::cout;
using std::endl;

//2、内部类 + 静态数据成员
class Singleton
{
public:
    static Singleton *getInstance()
    {
        if(nullptr == _pInstance)
        {
            _pInstance = new Singleton();
        }

        return _pInstance;
    }

    static void destroy()
    {
        if(_pInstance)
        {
            delete _pInstance;
            _pInstance = nullptr;
        }
    }
private:
    Singleton()
    {
        cout << "Singleton()" << endl;
    }

    ~Singleton()
    {
        cout << "~Singleton()" << endl;
    }
private:
    class AutoRelease
    {
    public:
        AutoRelease()
        {
            cout << "AutoRelease()" << endl;
        }
    
        ~AutoRelease()
        {
            cout << "~AutoRelease()" << endl;
            if(_pInstance)
            {
                delete _pInstance;
                _pInstance = nullptr;
            }
        }
    };
private:
    static Singleton *_pInstance;
    static AutoRelease _auto;
};

Singleton *Singleton::_pInstance = nullptr;
Singleton::AutoRelease  Singleton::_auto;

int main(int argc, char **argv)
{
    Singleton *ps1 = Singleton::getInstance();
    /* Singleton::AutoRelease ar;//栈对象//error */

    /* Singleton::destroy(); */
    return 0;
}
//③atexit + 饿汉模式
#include <stdlib.h>
#include <iostream>

using std::cout;
using std::endl;

//3、atexit + 饿汉模式

class Singleton
{
public:
    static Singleton *getInstance()
    {
        //在多线程环境下不安全
        if(nullptr == _pInstance)
        {
            _pInstance = new Singleton();
            atexit(destroy);
        }

        return _pInstance;
    }

    static void destroy()
    {
        if(_pInstance)
        {
            delete _pInstance;
            _pInstance = nullptr;
        }
    }
private:
    Singleton()
    {
        cout << "Singleton()" << endl;
        /* atexit(destroy); */
    }

    ~Singleton()
    {
        cout << "~Singleton()" << endl;
    }
private:
    static Singleton *_pInstance;
};

/* Singleton *Singleton::_pInstance = nullptr;//饱汉(懒汉)模式 */
Singleton *Singleton::_pInstance = getInstance();//饿汉模式

int main(int argc, char **argv)
{
    Singleton *ps1 = Singleton::getInstance();
    Singleton *ps2 = Singleton::getInstance();
    /* Singleton::AutoRelease ar;//栈对象//error */

    /* Singleton::destroy(); */
    return 0;
}
//④atexit+pthread_once形式,平台相关
//编译加上-lpthread
//得加头文件pthread.h
#include <pthread.h>
#include <stdlib.h>
#include <iostream>

using std::cout;
using std::endl;

//4、pthread_once + atexit(平台相关)

class Singleton
{
public:
    static Singleton *getInstance()
    {
        pthread_once(&_once, init);

        return _pInstance;
    }

    static void init()
    {
        _pInstance = new Singleton();
        atexit(destroy);
    }

    static void destroy()
    {
        if(_pInstance)
        {
            delete _pInstance;
            _pInstance = nullptr;
        }
    }
private:
    Singleton()
    {
        cout << "Singleton()" << endl;
        /* atexit(destroy); */
    }

    ~Singleton()
    {
        cout << "~Singleton()" << endl;
    }
private:
    static Singleton *_pInstance;
    static pthread_once_t _once;
};

Singleton *Singleton::_pInstance = nullptr;//饱汉(懒汉)模式
/* Singleton *Singleton::_pInstance = getInstance();//饿汉模式 */
//pthread_once初始化
pthread_once_t Singleton::_once = PTHREAD_ONCE_INIT;

int main(int argc, char **argv)
{
    Singleton *ps1 = Singleton::getInstance();
    Singleton *ps2 = Singleton::getInstance();
    /* Singleton::AutoRelease ar;//栈对象//error */

    /* Singleton::destroy(); */
    return 0;
}

3.std::string底层实现

(1)string三种实现版本
1)深拷贝(浅拷贝
2)写时复制 浅拷贝 + 引用计数
3)短字符串优化 当字符串的长度小于等于15字节时候,放栈上;当字符串长度大于16字节的时候,就放在堆上

(2)查看ubuntu版本信息

lsb_release -a

cat /proc/version
14.04string有8个字节,18.04有32个字节
18.04用的不是写时复制,而是短字符串优化

(3)引用计数放哪里?

1、全局静态不行
2、栈不行, const String &rhs,const是常量不能修改
3、文字常量区 程序代码 只读段, 引用计数会进行修改,也不行
4、只能放在堆上,其实在堆上任何位置都可以,只是为了好获取将将引用计数与数据放在一起,并且最好在数据前面,这样当数据变化的时候不会移动引用计数的位置

引用计数相关代码

//cowstring.cc
#include <string.h>
#include <iostream>

using std::cout;
using std::endl;

class String
{
public:
    //String s1;
    String()
    //5表示4个字节的引用技术和1一个字节的'\0'
    //4表示指针从引用计数的位置移动到字符串开始的位置
    : _pstr(new char[5]() + 4)
    {
        cout << "String()" << endl;
        //(_pstr-4)表示指向引用计数
        //(int *)表示强转成Int类型的指针
        //要给里面引用计数赋值,所以要用*解引用
        //*(int *)(_pstr-4)=1
        initRefCount();
    }

    //String s1("hello");
    String(const char *pstr)
    : _pstr(new char[strlen(pstr) + 5]() + 4)
    {
        cout << "String(const char *)" << endl;
        strcpy(_pstr, pstr);
        //*(int *)(_pstr-4)=1
        initRefCount();
    }

    //String s2 = s1
    String(const String &rhs)
    : _pstr(rhs._pstr)
    {
        cout << "String(const String &)" << endl;
        //++*(int *)(_pstr-4);
        increaseRefCount();
    }

    //String s3("world");
    //s3 = s1;
    //赋值运算符函数
    String &operator=(const String &rhs)
    {
        cout << "String &operator=(const String &)" << endl;

        if(this != &rhs)//1、自复制
        {
            release();//2、释放左操作数

            //s3和s1指向同一片空间
            _pstr = rhs._pstr;//3、浅拷贝
            //--*(int *)(_pstr-4);
            increaseRefCount();
        }

        return *this;//4、返回*this
    }

    //s3[0] = 'H';
    //写时复制
    char &operator[](size_t idx)
    {
        if(idx < size())
        {
            if(getRefCount() > 1)//是共享,共享次数较多
            {
                //先申请堆空间
                char *ptmp = new char[strlen(_pstr) + 5]() + 4;
                //然后把数据靠过来
                strcpy(ptmp, _pstr);
                //s3要和s2、s1脱离了,把引用计数--
                decreaseRefCount();
                //把ptmp赋给_pstr
                _pstr = ptmp;
                //初始化引用计数为1
                initRefCount();
            }
            return _pstr[idx];
        }
        else
        {
            static char nullchar = '\0';
            return nullchar;
        }
    }

    ~String()
    {
        cout << "~String()" << endl;
        release();
    }

    const char *c_str() const
    {
        return _pstr;
    }

    int getRefCount() const
    {
        return *(int *)(_pstr - 4);
    }

    size_t size() const
    {
        return strlen(_pstr);
    }

    void initRefCount()
    {
        *(int *)(_pstr - 4) = 1;
    }

    void increaseRefCount()
    {
        ++*(int *)(_pstr - 4);
    }

    void decreaseRefCount()
    {
        --*(int *)(_pstr - 4);
    }

    void release()
    {
        decreaseRefCount();
        if(0 == getRefCount())
        {
            delete [] (_pstr - 4);
        }
    }

    friend std::ostream &operator<<(std::ostream &os, const String &rhs);
private:
    char *_pstr;
};

//输出流运算符
std::ostream &operator<<(std::ostream &os, const String &rhs)
{
    if(rhs._pstr)
    {
        os << rhs._pstr;
    }
    return os;
}

void test()
{
    String s1("hello");
    cout << "s1 = " << s1 << endl;
    //看s1的地址
    printf("s1's address: %p\n", s1.c_str());
    //打印引用计数
    printf("s1's RefCount = %d\n", s1.getRefCount());

    cout << endl;
    String s2 = s1;
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    printf("s1's address: %p\n", s1.c_str());
    printf("s2's address: %p\n", s2.c_str());
    printf("s1's RefCount = %d\n", s1.getRefCount());
    printf("s2's RefCount = %d\n", s2.getRefCount());

    cout << endl;
    String s3("world");
    cout << "s3 = " << s3 << endl;
    printf("s3's address: %p\n", s3.c_str());
    printf("s3's RefCount = %d\n", s3.getRefCount());

    cout << endl << "执行s3 = s1操作" << endl;
    s3 = s1;
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    printf("s1's address: %p\n", s1.c_str());
    printf("s2's address: %p\n", s2.c_str());
    printf("s3's address: %p\n", s3.c_str());
    printf("s1's RefCount = %d\n", s1.getRefCount());
    printf("s2's RefCount = %d\n", s2.getRefCount());
    printf("s3's RefCount = %d\n", s3.getRefCount());


    cout << endl << "对s3[0] = \'H\'" << endl;
    //对s3进行写时复制
    s3[0] = 'H';
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    printf("s1's address: %p\n", s1.c_str());
    printf("s2's address: %p\n", s2.c_str());
    printf("s3's address: %p\n", s3.c_str());
    printf("s1's RefCount = %d\n", s1.getRefCount());
    printf("s2's RefCount = %d\n", s2.getRefCount());
    printf("s3's RefCount = %d\n", s3.getRefCount());

    //需要区分读和写,现在写没问题,读有bug
    cout << endl << "对s1[0]读操作的时候" << endl;
    cout << "s1[0] = " << s1[0] << endl;
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    printf("s1's address: %p\n", s1.c_str());
    printf("s2's address: %p\n", s2.c_str());
    printf("s3's address: %p\n", s3.c_str());
    printf("s1's RefCount = %d\n", s1.getRefCount());
    printf("s2's RefCount = %d\n", s2.getRefCount());
    printf("s3's RefCount = %d\n", s3.getRefCount());
}

int main(int argc, char **argv)
{
    test();
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值