当前位置: 首页 > 编程日记 > 正文

【C++】C/C++ 中 static 的用法全局变量与局部变量

C/C++ 中 static 的用法全局变量与局部变量

目录

1. 什么是static?

1.1 static 的引入

1.2 静态数据的存储

2. 在 C/C++ 中static的作用

2.1 总的来说

2.2 静态变量与普通变量

2.3 静态局部变量有以下特点:

实例

3. static 用法

3.1 在 C++ 中

3.2 静态类相关

3.3 总结:

实例


1. 什么是static?

static 是 C/C++ 中很常用的修饰符,它被用来控制变量的存储方式和可见性。

1.1 static 的引入

函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义为全局的变量,但定义一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅只受此函数控制)。static 关键字则可以很好的解决这个问题

另外,在 C++ 中,需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见时,可将其定义为静态数据。

1.2 静态数据的存储

全局(静态)存储区:分为 DATA 段和 BSS 段。DATA 段(全局初始化区)存放初始化的全局变量和静态变量;BSS 段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BBS段在程序执行之前会被系统自动清0,所以未初始化的全局变量和静态变量在程序执行之前已经为0。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。

在 C++ 中 static 的内部实现机制:静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化

这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有类的成员函数定义三是应用程序的 main() 函数前的全局数据声明和定义处。

静态数据成员要实际地分配空间,故不能在类的声明中定义(只能声明数据成员)。类声明只声明一个类的"尺寸和规格",并不进行实际的内存分配,所以在类声明中写成定义是错误的它也不能在头文件中类声明的外部定义,因为那会造成在多个使用该类的源文件中,对其重复定义。

static 被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间,静态数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。

优势:可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。


2. 在 C/C++ 中static的作用

2.1 总的来说

  • (1)在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。

  • (2)static 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以。

  • (3)static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。初始化的时候自动初始化为 0。

  • (4)不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用 static 修饰。

  • (5)考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用 static)。

2.2 静态变量与普通变量

静态全局变量有以下特点:

  • (1)静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量;

  • (2)未经初始化的静态全局变量会被程序自动初始化为0(在函数体内声明的自动变量的值是随机的,除非它被显式初始化,而在函数体外被声明的自动变量也会被初始化为 0);

  • (3)静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的。

优点:静态全局变量不能被其它文件所用;其它文件中可以定义相同名字的变量,不会发生冲突。

(1)全局变量和全局静态变量的区别

  • 1)全局变量是不显式用 static 修饰的全局变量,全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过 extern 全局变量名的声明,就可以使用全局变量。

  • 2)全局静态变量是显式用 static 修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用 extern 声明也不能使用。

2.3 静态局部变量有以下特点:

  • (1)该变量在全局数据区分配内存;

  • (2)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化

  • (3)静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为 0;

  • (4)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。

一般程序把新产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。

看下面的例子:

实例

//example:
#include <stdio.h>  
#include <stdlib.h>  
int k1 = 1;
int k2;
static int k3 = 2;
static int k4;
int main()
{static int m1 = 2, m2;int i = 1;char*p;char str[10] = "hello";char*q = "hello";p = (char *)malloc(100);free(p);printf("栈区-变量地址    i:%p\n", &i);printf("栈区-变量地址   p:%p\n", &p);printf("栈区-变量地址 str:%p\n", str);printf("栈区-变量地址   q:%p\n", &q);printf("堆区地址-动态申请:%p\n", p);printf("全局外部有初值 k1:%p\n", &k1);printf("   外部无初值 k2:%p\n", &k2);printf("静态外部有初值 k3:%p\n", &k3);printf("   外静无初值 k4:%p\n", &k4);printf("  内静态有初值 m1:%p\n", &m1);printf("  内静态无初值 m2:%p\n", &m2);printf("    文字常量地址:%p, %s\n", q, q);printf("      程序区地址:%p\n", &main);return 0;
}

输出结果如下:

img


3. static 用法

3.1 在 C++ 中

static 关键字最基本的用法是:

  • 1、被 static 修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要 new 出一个类来

  • 2、被 static 修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要 new 出一个类来

被 static 修饰的变量、被 static 修饰的方法统一属于类的静态资源,是类实例之间共享的,换言之,一处变、处处变。

在 C++ 中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。

静态成员的定义或声明要加个关键 static。静态成员可以通过双冒号来使用即 <类名>::<静态成员名>

3.2 静态类相关

通过类名调用静态成员函数和非静态成员函数:

class Point  
{  
public:   void init()  {    }  static void output()  {  }  
};  
void main()  
{  Point::init();  Point::output();  
}

img

报错:

'Point::init' : illegal call of non-static member function

结论 1:

不能通过类名来调用类的非静态成员函数必须通过对象实例化来调用。

通过类的对象调用静态成员函数和非静态成员函数。

class Point  
{  
public:   void init()  {    }  static void output()  {  }  
}; 
void main()  
{  Point pt;  pt.init();  pt.output();  
}

编译通过。

结论 2

类的对象可以使用静态成员函数和非静态成员函数。

在类的静态成员函数中使用类的非静态成员。

#include <stdio.h>  
class Point  
{  
public:   void init()  {    }  static void output()  {  printf("%d\n", m_x);  }  
private:  int m_x;  
};  
void main()  
{  Point pt;  pt.output();  
}

编译出错:

error C2597: illegal reference to data member 'Point::m_x' in a static member function

因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样。

结论3:静态成员函数中不能引用非静态成员。

在类的非静态成员函数中使用类的静态成员。

class Point  
{  
public:   void init()  {    output();  }  static void output()  {  }  
};  
void main()  
{  Point pt;  Pt.init();pt.output();  
}

编译通过。

结论 4:类的非静态成员函数可以调用静态成员函数,但反之不能。

使用类的静态成员变量。

#include <stdio.h>  
class Point  
{  
public:   Point()  {    m_nPointCount++;  }  ~Point()  {  m_nPointCount--;  }  static void output()  {  printf("%d\n", m_nPointCount);  }  
private:  static int m_nPointCount;  
};  
void main()  
{  Point pt;  pt.output();  
}

Ctrl+F7 编译无错误,按 F7 生成 EXE 程序时报链接错误。

error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA)

这是因为类的静态成员变量在使用前必须先初始化。

main() 函数前加上 int Point::m_nPointCount = 0; 再编译链接无错误,运行程序将输出 1。

结论 5类的静态成员变量必须先初始化再使用。

思考总结:静态资源属于类,但是是独立于类存在的。从 生命历程来看类的加载机制的角度讲,静态资源是类初始化的时候加载的,而非静态资源是类实例化对象的时候加载的。 类的初始化早于类实例化对象,比如 Class.forName("xxx") 方法,就是初始化了一个类,但是并没有实例化对象,只是加载这个类的静态资源罢 了。所以对于静态资源来说,它是不可能知道一个类中有哪些非静态资源的;但是对于非静态资源来说就不一样了,由于它是实例化对象出来之后产生的,因此属于类的这些东西它都能认识。所以上面的几个问题答案就很明确了:

  • 1)静态方法能不能引用非静态资源?不能,实例化对象的时候才会产生的东西,对于初始化后就存在的静态资源来说,根本不认识它。

  • 2)静态方法里面能不能引用静态资源?可以,因为都是类初始化的时候加载的,大家相互都认识。

  • 3)非静态方法里面能不能引用静态资源?可以,非静态方法就是实例方法,那是实例化对象之后才产生的,那么属于类的内容它都认识。

static 修饰类:这个用得相对比前面的用法少多了,static 一般情况下来说是不可以修饰类的, 如果 static 要修饰一个类,说明这个类是一个静态内部类(注意 static 只能修饰一个内部类),也就是匿名内部类。像线程池 ThreadPoolExecutor 中的四种拒绝机制 CallerRunsPolicy、AbortPolicy、DiscardPolicy、 DiscardOldestPolicy 就是静态内部类。静态内部类相关内容会在写内部类的时候专门讲到。)

结论 6静态成员函数

如果把函数成员声明为静态的,就可以把函数与类的任何特定对象独立开来。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问。

静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。

静态成员函数有一个类范围,他们不能访问类的 this 指针。您可以使用静态成员函数来判断类的某些对象是否已被创建。

静态成员函数与普通成员函数的区别:

  • 静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
  • 普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针。

3.3 总结:

  • (1)静态成员函数中不能调用非静态成员。

  • (2)非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。

  • (3)静态成员变量使用前必须先初始化(如 int MyClass::m_nNumber = 0;),否则会在 linker 时出错。

一般总结:在类中,static 可以用来修饰静态数据成员和静态成员方法。

静态数据成员

  • (1)静态数据成员可以实现多个对象之间的数据共享,它是类的所有对象的共享成员,它在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。

  • (2)静态数据成员是在程序开始运行时被分配空间,到程序结束之后才释放,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。

  • (3)静态数据成员可以被初始化,但是只能在类体外进行初始化,若未对静态数据成员赋初值,则编译器会自动为其初始化为 0。

  • (4)静态数据成员既可以通过对象名引用,也可以通过类名引用。

静态成员函数

  • (1)静态成员函数和静态数据成员一样,他们都属于类的静态成员,而不是对象成员。

  • (2)非静态成员函数有 this 指针,而静态成员函数没有 this 指针。

  • (3)静态成员函数主要用来方位静态数据成员而不能访问非静态成员。

再给一个利用类的静态成员变量和函数的例子以加深理解,这个例子建立一个学生类,每个学生类的对象将组成一个双向链表,用一个静态成员变量记录这个双向链表的表头,一个静态成员函数输出这个双向链表。

实例

#include <stdio.h>
#include <string.h>
const int MAX_NAME_SIZE = 30;  class Student  
{  
public:  Student(char *pszName);~Student();
public:static void PrintfAllStudents();
private:  char    m_name[MAX_NAME_SIZE];  Student *next;Student *prev;static Student *m_head;
};  Student::Student(char *pszName)
{  strcpy(this->m_name, pszName);//建立双向链表,新数据从链表头部插入。this->next = m_head;this->prev = NULL;if (m_head != NULL)m_head->prev = this;m_head = this;  
}  Student::~Student ()//析构过程就是节点的脱离过程  
{  if (this == m_head) //该节点就是头节点。{m_head = this->next;}else{this->prev->next = this->next;this->next->prev = this->prev;}
}  void Student::PrintfAllStudents()
{for (Student *p = m_head; p != NULL; p = p->next)printf("%s\n", p->m_name);
}Student* Student::m_head = NULL;  void main()  
{   Student studentA("AAA");Student studentB("BBB");Student studentC("CCC");Student studentD("DDD");Student student("MoreWindows");Student::PrintfAllStudents();
}

程序将输出:

MoreWindows

DDD

CCC

BBB

AAA

相关文章:

浅谈C/C++中的static和extern关键字

一.C语言中的static关键字 在C语言中&#xff0c;static可以用来修饰局部变量&#xff0c;全局变量以及函数。在不同的情况下static的作用不尽相同。 (1)修饰局部变量 一般情况下&#xff0c;对于局部变量是存放在栈区的&#xff0c;并且局部变量的生命周期在该语句块执行结束时…

彩色直方图均衡化实现

#include <opencv2/opencv.hpp> int main() {// 图像获取及验证cv::Mat srcImage cv::imread("..\\images\\flower3.jpg");if( !srcImage.data ) return 1;// 存储彩色直方图及图像通道向量cv::Mat colorHeqImage; std::vector<cv::Mat> BGR_plane; …

二、python小功能记录——监听鼠标事件

1.原文链接 #-*- coding:utf-8 -*- from pynput.mouse import Button, Controller## ## 控制鼠标 ## # 读鼠标坐标 mouse Controller() print(The current pointer position is {0}.format(mouse.position)) # 设置鼠标坐标 mouse.position (10, 20) print(No…

【Smart_Point】C/C++ 中智能指针

C11智能指针 目录 C11智能指针 1.1 C11智能指针介绍 1.2 为什么要使用智能指针 1.2.1 auto_ptr&#xff08;C98的方案&#xff0c;C11已经抛弃&#xff09;采用所有权模式。 1.2.2 unique_ptr 1.2.3 shared_ptr 1.2.4 weak_ptr 1.3 share_ptr和weak_ptr的核心实现 1.…

Linux 虚拟内存和物理内存的理解【转】

转自:http://www.cnblogs.com/dyllove98/archive/2013/06/12/3132940.html 首先&#xff0c;让我们看下虚拟内存&#xff1a; 第一层理解 1. 每个进程都有自己独立的4G内存空间&#xff0c;各个进程的内存空间具有类似的结构 2. 一个新进程建立的时候&#xff0c…

直方图变换——查找

#include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> int main() {// 图像获取及验证cv::Mat srcImage cv::imread("..\\images\\flower3.jpg");if( !srcImage.data ) return 1;//…

【C++】C/C++ 中default/delete特性

C类的特殊成员函数及default/delete特性 本文内容侧重个人理解&#xff0c;深入理解其原理推荐https://www.geeksforgeeks.org 目录 目录 C类的特殊成员函数及default/delete特性 前言 1. 构造函数和拷贝构造函数 2. 拷贝赋值运算符 3. C11特性之default关键字(P237, P4…

Celery--任务调度利器

2019独角兽企业重金招聘Python工程师标准>>> Celery文档: http://docs.jinkan.org/docs/celery/getting-started/first-steps-with-celery.html 安装celery和celery-with-redis pip install Celery pip install celery-with-redis开始编写task.py # tasks.py import…

直方图变换——累计

#include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> int main() {// 图像获取及验证cv::Mat srcImage cv::imread("..\\images\\flower3.jpg");if( !srcImage.data ) return 1;//…

iOS开发经验总结,我的2019进阶之路!

4G改变了生活&#xff0c;抓住机会的人已经在这个社会有了立足之地&#xff0c;马上迎来5G的时代&#xff0c;你做好准备了吗&#xff01;对于即将迎来的5G时代&#xff0c;无疑会是音视频的又一个高潮&#xff01;那么作为程序员的我们&#xff0c;应该怎么样去迎接它呢~~ 改变…

【C++】C/C++ 中多态情形下的虚函数表查看方法

1.查看工具 找到VS2017命令提示符工具 选择“VS 2017的开发人员命令提示符” 点击该选项栏&#xff0c;弹出“VS 2017的开发人员命令提示符”窗口 cd 控制进入带查看类躲在的位置 使用命令&#xff1a;cl /d1 reportSingleClassLayoutXXX [filename]&#xff0c;XXX表示类名&…

PHP中session_register函数详解用法

语法: boolean session_register(string name);注册新的变量。返回值: 布尔值函数种类: 资料处理内容说明本函数在全域变量中增加一个变量到目前的 Session 之中。参数 name 即为欲加入的变量名。成功则返回 true 值。假如在头文件&#xff0c;开启session,即使用session_start…

Fedora 提出统一流程,弃用上千 Python 2 软件包更可控

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; >>> Fedora 社区正在讨论弃用 Python 2 软件包的统一流程。 https://pythonclock.org Python 2 将于 2020 年 1 月 1 日正式退休&#xff0c;官方不再提供维护&#xff0c;当前倒计时不…

【C++】C++对象模型:对象内存布局详解(C#实例)

C对象模型&#xff1a;对象内存布局详解 0.前言 C对象的内存布局、虚表指针、虚基类指针解的探讨&#xff0c;参考。 1.何为C对象模型? 引用《深度探索C对象模型》这本书中的话&#xff1a; 有两个概念可以解释C对象模型&#xff1a; 语言中直接支持面向对象程序设计的部分…

Mybatis插件原理和PageHelper结合实战分页插件(七)

今天和大家分享下mybatis的一个分页插件PageHelper,在讲解PageHelper之前我们需要先了解下mybatis的插件原理。PageHelper的官方网站&#xff1a;https://github.com/pagehelper/Mybatis-PageHelper一、Plugin接口mybatis定义了一个插件接口org.apache.ibatis.plugin.Intercept…

直方图反向投影

#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> using namespace cv; using namespace std; int main() {// 加载源图像并验证cv::Mat srcImage cv::imread("..\\images\\hand1.jpg&quo…

Java异常处理12条军规

摘要&#xff1a; 简单实用的建议。 原文&#xff1a;Java异常处理12条军规公众号&#xff1a;Spring源码解析Fundebug经授权转载&#xff0c;版权归原作者所有。 在Java语言中&#xff0c;异常从使用方式上可以分为两大类&#xff1a; CheckedExceptionUncheckedException在Ja…

【Smart_Point】C/C++ 中独占指针unique_ptr

1. 独占指针unique_ptr 目录 1. 独占指针unique_ptr 1.1 unique_ptr含义 1.2 C11特性 1.3 C14特性 1.1 unique_ptr含义 unique_ptr 是 C 11 提供的用于防止内存泄漏的智能指针中的一种实现&#xff0c;独享被管理对象指针所有权的智能指针。unique_ptr对象包装一个原始指…

ORA-01940无法删除当前已连接用户

原文地址&#xff1a;ORA-01940无法删除当前已连接用户作者&#xff1a;17361887941)查看用户的连接状况 select username,sid,serial# from v$session ------------------------------------------ 如下结果&#xff1a; username sid serial# ------…

距离变换扫描实现

#include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> // 计算欧式距离 float calcEuclideanDistance(int x1, int y1, int x2, int y2) {return sqrt(…

『扩欧简单运用』

扩展欧几里得算法 顾名思义&#xff0c;扩欧就是扩展欧几里得算法&#xff0c;那么我们先来简单地回顾一下这个经典数论算法。 对于形如\(axbyc\)的不定方程&#xff0c;扩展欧几里得算法可以在\(O(log_2alog_2b)\)的时间内找到该方程的一组特解&#xff0c;或辅助\(gcd\)判断该…

【Smart_Point】C/C++ 中共享指针 shared_ptr

1. 共享指针 shared_ptr 目录 1. 共享指针 shared_ptr 1.1 共享指针解决的问题&#xff1f; 1.2 创建 shared_ptr 对象 1.3 分离关联的原始指针 1.4 自定义删除器 Deleter 1.5 shared_ptr 相对于普通指针的优缺点 1.6 创建 shared_ptr 时注意事项 1.1 共享指针解决的问…

对数变换的三种实现方法

#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> using namespace cv; // 对数变换方法1 cv::Mat logTransform1(cv::Mat srcImage, int c) {// 输…

eclipse编辑窗口不见了(打开左边的java、xml文件,中间不会显示代码)

转自&#xff1a;https://blog.csdn.net/u012062810/article/details/46729779?utm_sourceblogxgwz4 1. windows-->reset Perspective 窗口-->重置窗口布局 2. windows -> new windows 新窗口 当时手贱了一下&#xff0c;结果…

js的执行机制

javascript的运行机制一直困扰在我&#xff0c;对其的运行机制也是一知半解&#xff0c;在看了https://juejin.im/post/59e85eebf265da430d571f89#heading-10这篇文章后&#xff0c;有种茅塞顿开的感觉,下面是原文内容&#xff1a; 认识javascript javascript是一门单线程语言&…

【Smart_Point】unique_ptr中独占指针使用MakeFrame

1. DFrame使用方法 std::unique_ptr<deptrum::Frame> MakeFrame(deptrum::FrameType frame_type,int width,int height,int bytes_per_pixel,void* data,uint64_t timestamp,int index,float temperature) {std::unique_ptr<deptrum::Frame> frame{std::make_uniq…

最大熵阈值分割

#include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> using namespace std; using namespace cv; // 计算当前的位置的能量熵 float caculateCurrentE…

php登录注册

php 登录注册 注册代码&#xff1a;register.php <style type"text/css">form{width:300px;background-color:#EEE0E5;margin-left:300px;margin-top:30px;padding:30px;}button{margin-top:20px;} </style> <form method"post"> <la…

【C++】C/C++ 中的单例模式

目录 part 0&#xff1a;单例模式3种经典的实现方式 Meyers Singleton Meyers Singleton版本二 Lazy Singleton Eager Singleton Testing part 1&#xff1a;C之单例模式 动机 实现一[线程不安全版本] 实现二[线程安全&#xff0c;锁的代价过高] 锁机制 实现三[双检…

计算图像波峰点

#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> #include <iostream> #include <vector> using namespace std; using namespace cv; // 计算图像的波峰…