C++静态局部对象
7.5局部对象
在C++语言中,对于每一个变量和对象,都有其各自的作用域和生存期,这两个概念一个是空间的,一个是时间的。对象的作用域指的是该变量的程序文本区,对象的生存期则是程序执行过程中对象存在的时间。
7.5.1自动对象
只有当定义它的函数被调用的时候才存在的对象称为自动对象,自动对象在每次调用函数时创建和销毁。
局部变量所对应的自动对象在函数控制经过变量定义语句时创建。如果在定义时提供了初始化,那么每次创建对象时,对象都会被初始化为指定的初值。对于未初始化的内置类型局部变量,其初值是不确定的随机值(当然这里的随机指的是伪随机)。当函数调用结束时,自动对象就会被撤销。
7.5.2 静态局部对象
一个变量如果位于函数的作用域内,但生存期却跨越了这个函数的多次调用,这种变量往往很有用,则应该讲这样的对象定义为static。
static局部对象确保不迟于在程序执行流程第一次经过该对象的定义语句时进行初始化。这种对象一旦被创建,在程序结束前都不会被撤销。看下面的这个例子,这个函数计算了自己被调用的次数:
#include <iostream>
using namespace std; size_t count_calls()
{
static size_t ctr = 0;
return ++ctr;
} int main()
{
for(int i = 0; i < 10; i++)
{
cout << count_calls() << endl;
} return 0;
}
程序执行结果:这个程序一次输出1到10(包括10)的整数。
问题与解决
第一次读到上面的程序的时候,有一点疑问:上面的那句话static size_t ctr = 0会不会在每次调用函数的时候把ctr弄成0呢?
当然答案是不会的,不然这个static不就等于不写了吗?
这里还是要搞清楚一个概念,那就是变量的初始化和赋值两种不同的操作。任何变量的初始化都只有一次,就是在变量定义的时候,也就是内存刚刚分配之后的瞬间;赋值操作是修改变量内原来的值(里面的值可能是初始化得到的,也可能是上次赋值得到的)。
静态全局变量就是在main函数调用之前调用的。
静态局部变量则在第一次使用之前调用的。
静态变量的初始化是在首次执行到初始化语句时间执行的,编译时在初始化语句之前放置一个标志位,每次进行判断,倘若需要初始化则执行初始化操作,否则不执行。上面的那句static size_t ctr = 0就是静态局部变量的初始化,只是在第一次调用这个函数,初始化这个静态对象的时候才会被执行,后面的其他次的调用该函数是不会执行这句话的。
那么为什么普通局部变量在每次函数调用的时候都要执行size_t ctr = 0这句话呢?(假设这个函数中有这么一句话)因为它是普通的局部变量,上次的已经被销毁了,这次是重新开辟的内存空间,要对新的内存空间也就是对象进行初始化。而静态局部对象在上次调用之后没有被销毁,所以这次调用不会分配内存空间,当然不用执行初始化的语句了。
实例展示
下面的四个函数,不同的地方仅仅差别在于定义的变量的属性(是不是static)和有没有初始化。
static int ctr = 0仅仅起的是一个初始化的作用,在若干次执行test1()函数时,static int ctr = 0;只在第一次test1()函数被调用的时候初始化为0,当test1()第二次或更多次被调用时,ctr为保存的上一次的值。
#include <iostream> using namespace std; void test1(void)
{
static int ctr = 0; //静态变量,初始化为0
cout << "ctr1_1:" << ctr << endl; ++ctr;
cout << "ctr1_2:" << ctr << endl; } void test2(void)
{
int ctr = 0; //非静态变量,初始化为0
cout << "ctr2_1:" << ctr << endl; ++ctr;
cout << "ctr2_2:" << ctr << endl;
} void test3(void)
{
static int ctr; //静态变量,未初始化
cout << "ctr3_1:" << ctr << endl; ++ctr;
cout << "ctr3_2:" << ctr << endl;
} void test4(void)
{
int ctr; //非静态变量,未初始化
cout << "ctr4_1:" << ctr << endl; ++ctr;
cout << "ctr4_2:" << ctr << endl;
} int main()
{
for(int i = 0; i < 4; i++)
{
test1();
test2();
test3();
test4();
cout << "--------------" << endl;
} return 0;
}
程序执行结果:
C++静态局部对象的更多相关文章
- C++静态变量对象的建立和删除,兼论MFC开始运行的起点(全局对象)
看了不少C++书,当讲到静态变量的时候,总是以int成员来举例,是啊,这样很好理解.但是如果这个静态变量是一个对象行不行呢?不仅行,有时候还非常必要,而且别有洞天. 比如: // .h 文件 clas ...
- 关于C++函数返回局部对象的详细分析
以前一直挺好奇的,C++是怎么在函数内返回一个局部对象的.因为按照我之前的想法,函数返回一个基本类型的值是通过存放到ecx实现的(关于浮点不了解),但是局部对象又是比较大的,很明显不能使用寄存器作为通 ...
- “全栈2019”Java第九十五章:方法中可以定义静态局部内部类吗?
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- c/c++不能返回局部对象和局部变量的指针或引用解释
在编写c/c++代码时,调用函数的书写让程序变得整洁易读,但是调用函数的返回值(局部变量的返回值,变量,结构体,数组等)也有注意事项.c/c++严禁返回局部变量的指针或引用. 其实函数的返回值的规则非 ...
- 条款31: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用
先看第一种情况:返回一个局部对象的引用.它的问题在于,局部对象 ----- 顾名思义 ---- 仅仅是局部的.也就是说,局部对象是在被定义时创建,在离开生命空间时被销毁的.所谓生命空间,是指它们所在的 ...
- C++ //拷贝构造函数调用时机//1.使用一个已经创建完毕的对象来初始化一个新对象 //2.值传递的方式给函数参数传值 //3.值方式返回局部对象
1 //拷贝构造函数调用时机 2 3 4 #include <iostream> 5 using namespace std; 6 7 //1.使用一个已经创建完毕的对象来初始化一个新对象 ...
- jquery源码解析:jQuery静态属性对象support详解
jQuery.support是用功能检测的方法来检测浏览器是否支持某些功能.针对jQuery内部使用. 我们先来看一些源码: jQuery.support = (function( support ) ...
- PHP 简单面向对象 验证码类(静态实例对象调用)
没事写了一个简单的面向对象验证码类,可以直接使用(替换一下字体路径) <?php class authCode { private static $instance = null; #实例对象 ...
- C++ 静态对象
一:什么是静态对象? 对象的存储方式是静态的. 局部静态对象和类的静态对象. 局部静态对象:一个变量在函数内部定义,其生命周期跨越了该函数的多次调用.局部对象确保不迟于 ...
随机推荐
- 一个Windows C++的线程类实现
Thread.h [cpp] view plaincopy #ifndef __THREAD_H__ #define __THREAD_H__ #include <string> #inc ...
- Sql Server 2008 卸载重新安装失败的解决办法!(多次偿试,方法均有效!)
Sql Server 2008 卸载重新安装失败的解决办法!(多次偿试,方法均有效!) 1.控制面板中卸载所有带sql server的程序. 2.在C盘C:\Program Files中sqlserv ...
- SPOJ 3267 求区间不同数的个数
题意:给定一个数列,每次查询一个区间不同数的个数. 做法:离线+BIT维护.将查询按右端点排序.从左到右扫,如果该数之前出现过,则将之前出现过的位置相应删除:当前位置则添加1.这样做就保证每次扫描到的 ...
- MySQL数据处理函数
数据处理函数 有时从数据库表中获取到的数据须要进行一些处理. 如将小写字母替换为对应的大写字母.这个处理过程能够在客户机上进行.也能够在数据库上进行. 数据库上进行会更高效.数据库中有对应的数据处理函 ...
- 【九】注入框架RoboGuice使用:(Your First Injected Service and BroadcastReceiver)
上一篇我们简单的介绍了一下RoboGuice的使用([八]注入框架RoboGuice使用:(Your First Injected Fragment)),今天我们来看下服务(Service)和广播接受 ...
- C#反射调用程序集类中方法
建立类 class OperatorClass { /// <summary> /// 加法 /// </summary> /// <param name="x ...
- Oracle 关于V$OPEN_CURSOR
参考链接:http://www.askmaclean.com/archives/about-dynamic-view-open_cursor.html#wrap 在之前的一次讨论中,有同行指出V$OP ...
- IO与文件读写---使用Apache commons IO包提高读写效率
觉得很不错,就转载了, 作者: Paul Lin 首先贴一段Apache commons IO官网上的介绍,来对这个著名的开源包有一个基本的了解:Commons IO is a library of ...
- HOJ1008
#include<iostream> using namespace std; int main(){ ; ; ){ ; ; numTemp = N; ) && count ...
- TCP的流量控制
TCP协议作为一个可靠的面向字节流的传输协议,其可靠性和流量控制由滑动窗口协议保证,而拥塞控制则由控制窗口结合一系列的控制算法实现. 要区分TCP的流量控制和拥塞控制: 流量控制是发送方的发送数据的速 ...