首页 > 编程语言 >C++基础知识系列-3

C++基础知识系列-3

时间:2023-04-15 14:33:43浏览次数:39  
标签:系列 对象 C++ 基础知识 继承 single 线程 内存 构造函数

设计模式

GoF设计模式清单

工厂模式和抽象工厂模式在实际开发中使用较少;

单例模式是重点,针对一个类的唯一实例;
单例模式:通过设计的接口getInstance()获得对象,在接口内部设计只能有一个对象。
将类的构造函数定义为私有属性【外部不能创建对象】;定义一个私有的类的静态私有成员变量;提供一个公有的静态方法,负责一次性实例化或返回实例对象。

单例模式最推荐的方式:局部静态变量

template<typename T>
class Singlenton
{
public:
	static T& GetInstance()
    {
        //变量初始化的时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束
        //解决方式:加锁,在一个线性执行的时候,先禁用其他的线程??
        static T instance;
        //返回的是一个引用,不是指针,是因为指针会被delete,在下续使用中可能被delete,出现BUG。
        return &instance;
    }
    Singlenton(T&&) = delete;
    Singlenton(const T&) = delete;
    void operator = (const T&) = delete;
    
protected:
    //将类的构造函数定义为私有属性【外部不能创建对象
	Singlenton() = default;
    virtual ~Singlenton() = default;
}

传统的单例模式-饿汉式:一次加载完,加载类的时候速度比较慢,但以后获的对象时的速度比较快;

传统的单例模式-懒汉式:延迟加载机制,需要这个对象的时候才去实例化加载类的时候速度较快,但以后获得对象时的速度较慢。该对象在整个应用的生命周期只有一部分时间占用资源
存在线程安全)面临多线程访问的安全性问题,需要做双重锁定处理才能保证安全。

双重锁定好处:在加锁前检查锁标志,用于减少锁的开销。

双重锁定问题

/new的步骤:1.申请一块内存。2.执行构造函数对其进行初始化。3.将地址赋值给 ptr。
但是实际上编译器对指令进行重新排序之后的实现步骤是这样的:1. 申请一块内存。2.将地址赋值给 ptr。3.执行构造函数对其进行初始化。
由于线程的切换是按指令切换的,也就是说在执行这一个指令之前或者之后切换到另一个线程,那么当线程 A 在执行完前两步(1.申请一块内存。2.将地址赋值给 ptr) 的时候,此时 ptr 已经有了值,那么此时切换到线程 B 的时候,判断 ptr 不为 NULL,然后将其返回,那么线程 B 所得到的 ptr 是一个还没有进行初始化的一个 对象。

结合代码看:

KSingletonLazy* KSingletonLazy::getInstance()
{
	//但是还没调用构造函数的时候,线程B执行到第一个if(),判断m_single此时不为空,则返回该变量,
	//然后调用该对象的函数,但是该对象还没有进行构造。
    if (m_single == nullptr)
    {
        m_mutex(lock);
		if (m_single == nullptr)
        {
            //双锁的线程安全问题:不同的编译器表现是不一样的。可能先将该内存地址赋给m_single,然后再调用构造函数。
            //这时线程A恰好申请完成内存,并且将内存地址赋给m_single,	
            m_single = new KSingletonLazy; //这条语句做了三件事:第一件事申请一块内存,第二件事调用构造函数,第三件是将该内存地址赋给m_single。
        }
        m_mutex(lock);
    }
	return m_single;
}

建造者模式:在实际开发中,在不影响代码可读性的前提下,要尽量避免继承,组合优于继承

原型模式:针对被实例化的类

设计模式原则

题外tips

避免不必要的for(),减少开销,程序如果不能运行,就让其尽早崩溃,释放内存。

使用智能指针也会存在一定的内存开销,因为要维护一个计数器;

生存周期:维护生存周期的小技巧:使用缩进;

内存泄漏:指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。最终的结果就是导致OOM。
也就是new完使用完了以后不能delete,结果自己也不能访问,系统也不能进行分配。

内存泄漏的三种情况
1,指针重新赋值
2,错误的内存释放
3,返回值的不正确处理

程序崩溃的三种情况
1、分段错误:尝试访问系统中不存在的内存位置;在只读存储器位置上进行写操作;堆栈溢出,无法终止内存位置的递归;
2、缓冲区溢出:程序在将数据写入缓冲区时会溢出缓冲区的边界并覆盖相邻的内存位置。
3、内存泄露:如上↑

查看内存空间 :调试-窗口-内存-xxx

工厂模式

简单工厂模式:常用&实用

定义一个基类的好处:便于实现面向对象的多态。

抽象工厂模式

组合优于继承:entity component

​ --继承优点:父类的大部分功能可以通过继承关系自动进入子类;修改或扩展继承而来的属性和方法较为容易。
​ --继承缺点:一个类只能有一个父类,不能同时继承两个父类,因此无法通过继承的方式,重用多个类中的代码;父类的属性和方法,子类是无条件继承的,容易造成方法的污染。

用”has-a”(有什么或用什么)去替代”is-a”(是什么)

​ --组合优点:用组合代替继承,把一些特征和行为抽取出来,形成工具类。然后通过组合成为当前类的属性。再调用其中的属性和行为达到代码重用的目的。
​ --组合优点:可以选择一个类中是否应该具有某种行为,从而决定应该聚合那些类,不应该聚合那些类。这样,通过聚合/组合关系,也可以避免继承所带的方法污染问题

代理模式

远程代理:为网络上的对象创建一个局部对象,所有网络通讯操作交给代理去做,让客户可以会忽略这些被代理的对象是不是远程的

虚拟代理:用于开销很大需要较长时间实例化的对象。

Copy-on-Write代理:虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。

智能引用代理:是指当调用真实对象时,代理处理另外一些事,比如记录对此对象的调用次数等。

C++中独有代理:一个私有类包含类的成员变量,在类中直接声明私有类的变量。最大好处是二进制兼容

//创建一个私有类包含类的成员变量
class WidgetPrivate
{
private :
    int color;
    int height;
}
class Widget
{
public:
    widget();
private:
    //在类中直接声明私有类的变量
    WidgetPrivate* data;
}

调试项目

.pdb文件

标签:系列,对象,C++,基础知识,继承,single,线程,内存,构造函数
From: https://www.cnblogs.com/wj0518/p/17321104.html

相关文章

  • C++基础知识系列-2
    C++11新特性C++11易用性改进静态断言使用范围几乎不受限制static_assert断言对象必须是常量表达式,编译期给出断言警告。用于ERROR提示强枚举类型//enum关键字enum class HighSchool: unsigned int {    student,    teacher,    principal};使用强......
  • Semantic Kernel 入门系列:
    当我们使用NativeFunction的时候,除了处理一些基本的逻辑操作之外,更多的还是需要进行外部数据源和服务的对接,要么是获取相关的数据,要么是保存输出结果。这一过程在SemanticKernel中可以被归类为Connector。Connector更像是一种设计模式,并不像Function和Memory一样有强制和明确......
  • 6、后端学习规划:Java学习 - 学习规划系列文章
          Java语言在现在的编程语言排行榜上也是前5的存在。经过这么些年的发展,Java的发展没有C#这么大,但是在编程领域,因为有MVC架构,以及Spring框架的支持,以及微服务架构等等,Java这些年也是风生水起,笔者认为Java在Web端倒是非常适合的,特别是企业应用等业务系统方面。 1......
  • C++ 测试框架 GoogleTest 初学者入门篇 丙
    theme:channing-cyan*以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「ENG八戒」https://mp.weixin.qq.com/s/RIztusI3uKRnoHVf0sloeg开发者虽然主要负责工程里的开发任务,但是每个开发完毕的功能都是需要开发者自测通过的,所以经常会听到开发者提起单元测试的......
  • 深度学习基础知识串烧
    ✅作者简介:热爱科研的算法开发者,Python、Matlab项目可交流、沟通、学习。......
  • Java基础知识点内部类之局部内部类和匿名内部类
    一:局部内部类1概述:将内部类定义在方法里面就叫做局部内部类。类似于方法里面的局部变量。2.注意点:外界无法直接使用,需要在方法内部创建对象并使用。3.该类可以直接访问外部类成员,也可以访问方法内的局部变量。publicclassOuter{publicstaticvoidshow(){......
  • Linux基本功系列-help命令
    1.help命令介绍help命令用于显示shell内部命令的帮助信息。help命令只能显示shell内部命令的帮助信息,而linux系统中绝大多数命令是外部命令,所以help命令的作用非常有限。而对于外部命令的帮助信息可以使man命令或者info命令查看。help命令可以放在命令前面,也可以放在命令后面,比如e......
  • C++实现职工管理系统
    使用C++编程实现——管理系统中需要实现的功能如下:退出管理程序:退出当前管理系统增加职工信息:实现批量添加职工功能,将信息录入到文件中,职工信息为:职工编号,姓名,部门编号显示职工信息:显示公司内部所有职工的信息删除离职职工:按照编号删除指定的职工修改职工信息:按照编号修改职工......
  • nvim-dap C++ cpptools
    https://github.com/microsoft/vscode-cpptoolsgccgdblocaldap=require("dap")dap.adapters.cppdbg={id='cppdbg',type='executable',command='c:\\gnu\\tool\\cpptools\\extension\\debugAdapters\......
  • C/C++人事信息系统[2023-04-15]
    C/C++人事信息系统[2023-04-15]课程设计题目1——链表综合算法设计一、设计内容已知简单的人事信息系统中职工记录包含职工编号(no)、职工姓名(name)部门名称(depname)、职称(title)和工资数(salary)等信息,设计并完成一个简单的人事信息管理系统,要求完成但不限于以下功能:(1)......