C++中局部静态(local static)的用法

在局部作用域中使用static来声明一个变量(静态局部Local static变量)

声明一个变量需要考虑两种情况:变量的生存期和变量的作用域
变量的生存期指的是变量实际存在的时间,换句话说,在它被删除之前,它会在我们的内存中存在多久。
变量的作用域是指我们可以访问变量的范围,即如果在一个函数内部声明一个变量,我们不能在其他的函数中访问它,因为我们声明的变量对于我们声明的函数是局部的。

原理解释

静态局部(local static) 变量允许我们声明一个变量,它的生存周期基本上相当于整个程序的生存期,然而它的作用范围被限制在这个函数内,但它其实和函数没有什么关系。即意味着你可以在任何作用域中声明这个,刚才只是用函数举个例子,这并不仅仅局限于函数内部,也可以在if语句中,也可以在任何位置。

这也是为什么函数的作用域中的static和类作用域中的static之间没有太大的区别,因为生存期实际上是相同的,唯一的区别是在类作用域中,类中的任何东西都可以访问它(这个静态变量)
然而如果你在函数的作用域中声明一个静态变量,那么它将是那个函数的局部变量,对类来说也是局部变量。

代码实现-函数

 # include <iostream>
using namespace std;

//int i = 0;将i=0;放到外面成为全局变量,会造成在任意地方都能访问i
void Function()
{
	//声明静态变量
	static int i = 0;
	//加入static即 static int i = 0;相当于将 int i = 0;放到函数外面成为全局变量.
    //区别在于加入static仍然是一个局部变量,而放到函数外面就是一个全局变量,导致在任何位置都可以访问
	i++;
	cout << i << endl;
	//不加入static,打印出i的值都是1,每次调用函数都重新对i赋初值
    //加入static后,生存周期并不局限于函数而是整个程序
}

int main()
{
	Function();
	//i = 10; 此时的i是未定义的,因为i是局部变量
	Function();
	Function();
	cin.get();
	return 0;
}
 

在上述的代码中,程序运行的结果就是1、2、3,i是静态局部变量,如果将程序中static去掉,程序运行的结果就是1、1、1,因为此时的i是局部变量。如果将int i = 0;放到函数外面会实现与静态布局变量相同的效果。一旦在主程序中改变i的值,打印的结果就会变化。如果是静态局部变量,改变i的值,会报错,因为i的作用域是在函数内部,是局部变量。

代码实现-类

单例类是指只存在一个实例的类,如果我想创建这个单例类而不使用静态局部作用域,我就需要创建静态的单例实例,可能是一个指针。

使用指针实现单例类

# include <iostream>
using namespace std;

//单例类是指只存在一个实例的类,如果我想创建这个单例类而不使用静态局部作用域,我就需要创建静态的单例实例,可能是一个指针
class Singleton
{
private:
	//声明了一个静态指针成员
	static Singleton* s_Instance; // s_Instance是Singleton类的一个实例的指针,存储着Singleton类的实例的地址,并且该实例被声明为static,无论创建多少个Singleton的实例,s_Instance都只有一个副本
public:
	static Singleton& Get() // 定义了一个静态函数,返回类型是Singleton&,表示返回一个对Singleton类型对象的引用
	{
		return *s_Instance;  
	} 
	//Get()是一个静态函数,因此可以通过类名直接调用,而不需要实例化对象,这个例子中,它充当了获取Singleton实例的全局访问点
	//返回类型是Singleton&,即Singleton类型的引用。
	// 引用是一个别名,它允许我们使用另一个对象的名称来访问同一对象。通过返回引用,而不是返回指针,我们可以避免在使用返回值时需要进行解引用操作
	//函数Get()返回的时s_Instance指针所指向的Singleton实例的引用。
	//通过返回引用,可以避免复制对象的开销,并确保在调用方修改实例时,这些修改也会影响到单例模式中的唯一实例。
	void Hello()  { }
};
//声明这个实例
Singleton* Singleton::s_Instance = nullptr;
//在类外进行静态成员的初始化是因为静态成员不属于类的任何实例,它们属于整个类。因此它们需要在类外进行初始化。通过在类外进行初始化,可以确保它们只有一个实例,而不是在每个文件中都有一个独立的实例
//静态成员变量需要在程序开始之前进行初始化,并且只有一个实例。
int main()
{
	//利用单例类
	Singleton::Get().Hello();
	cin.get();
	return 0;
}

Singleton* Singleton::s_Instance = nullptr;指的是静态成员变量的初始化,在类外进行静态成员的初始化是因为静态成员不属于类的任何实例,它们属于整个类。因此它们需要在类外进行初始化。通过在类外进行初始化,可以确保它们只有一个实例,而不是在每个文件中都有一个独立的实例。静态成员变量需要在程序开始之前进行初始化,并且只有一个实例。

static Singleton* s_Instance; 其中 s_Instance 是 Singleton 类的一个实例的指针,存储着 Singleton 类的实例的地址,并且该实例被声明为 static(静态),无论创建多少个Singleton的实例,s_Instance都只有一个副本。如果不了解静态(static),可以查看另一篇文章关于static(静态)在类和结构体中的用法。

static Singleton& Get() { return *s_Instance; } 定义了一个静态函数,返回类型是 Singleton& ,表示返回一个对 Singleton 类型对象的引用。Get()是一个静态函数,因此可以通过类名直接调用,而不需要实例化对象,这个例子中,它充当了获取Singleton实例的全局访问点。

函数Get()返回的时s_Instance指针所指向的Singleton实例的引用。通过返回引用,可以避免复制对象的开销,并确保在调用方修改实例时,这些修改也会影响到单例模式中的唯一实例。

解释一下引用(&)引用是一个别名,它允许我们使用另一个对象的名称来访问同一对象。通过返回引用,而不是返回指针,我们可以避免在使用返回值时需要进行解引用操作。

函数返回引用代码实现

#include <iostream>
using namespace std;

int globalValue = 10;

// 返回类型为 int&,表示返回 globalValue 的引用
int& getGlobalValue() {
    return globalValue;
}

int main() {
    // 打印当前的 globalValue
    cout << "Initial value: " << globalValue << endl; // 输出:Initial value: 10

    // 修改引用返回的值
    getGlobalValue() = 20; // getGlobalValue 返回 globalValue 的引用,然后将其修改为 20

    // 再次打印 globalValue,查看其是否被修改
    cout << "Modified value: " << globalValue << endl; // 输出:Modified value: 20

    return 0;
}

使用静态局部作用域实现单例类

# include <iostream>
using namespace std;

class Singleton
{
public:
	static Singleton& Get()
	{
        static Singleton s_Instance;
		return s_Instance;  
	} 
	void Hello()  { }
};

int main()
{
	//利用单例类
	Singleton::Get().Hello();
	cin.get();
	return 0;
}

静态局部变量不需要在类外初始化,而静态成员变量需要在类外进行初始化。

静态局部变量不需要在类外进行初始化,静态局部变量在函数内部声明,但是只会在第一次进入该函数是进行初始化,没有显示初始化就会被默认构造函数进行初始化,然后在函数生命周期结束时销毁。

静态成员变量需要在程序开始之前进行初始化,并且只有一个实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熬夜写代码的平头哥∰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值