存储类关键字
1 说明
存储类关键字是名称声明语法的decl-specifier-seq的一部分。和名称的作用域一起,控制着名称的两个独立属性,自动存储期和链接属性。
一次只能一个存储类关键字出现在声明语句中,thread_local是个例外,需要与static和或者extern结合使用。(C++11之后适用)
2 解释
3 存储期
所有的对象都具有下面这些存储类型中的一种:
4 链接
名称意指对象,引用,函数,类型,模板,命名空间,或数值(枚举器),都可以有链接属性。如果一个名称具有链接属性,那么在另一个作用域内声明而引入的相同名称就会被引用为同一个实体。如果在几个作用域内声明了具有相同名称的变量,函数,或另一个实体,但是又没有有效的链接属性,那么就会产生几个实体实例。
链接类型可以被分为下面三种:
(1)无链接。
这种方式适用于名称在它的作用域内的情况。下面的几种情况具有非链接属性:
(2)内部链接。
在当前的编译单元里能够被所有的作用域引用的名称。命名空间作用范围内声明的下面中的任何一种名称都具有内部链接属性:
另外,在不具名命名空间或者不具名命名空间内部的命名空间里声明的所有变量,即使明确使用extern声明,也是内部链接属性。
(3)外部链接
可被其它编译单元参考引用的名称,就具有外部链接属性。具有外部链接属性的变量和函数也具有语言链接属性,这使得链接不同程序语言写的编译单元成为可能。
任何在命名空间里声明的下列变量都具有外部链接属性,除非,命名空间是不具名的或者被一个不具名命名空间包含(C++11之后)。
首次声明在块作用域内的下列变量中任何一种都有外部链接属性:
5 静态局部变量
使用限定符static声明在块作用域内的变量具有static存储期,只有当第一次执行经过它们的声明时被初始化(除非它们的初始化是0或常量初始化,这种初始化可以在进入块作用域之前就已经完成)。在所有后面的调用中,声明都会被跳过,不执行。
如果初始化过程出现异常,那么不认为变量被初始化,再一次尝试控制经过声明语句时,还会初始化。
如果多个线程同时尝试初始化相同的静态变量,初始化也只会进行一次(对于使用std::cal_once的任意函数都能获得相似的行为)。
注意:这个功能的通常实现就是使用双重检查锁定模式,它可以减少已经初始化为局部静态和单个非原子boolean的比较产生的系统开销。
当程序exit时,调用块作用域的析构函数,但前提是初始化成功。
对于同一个内嵌函数(也许是隐含内嵌)的所有定义里的局部静态对象,都会被一个编译单元定义的相同的对象引用。
6 注意
在C语言中,在顶层命名空间作用域(相当于C的文件范围)内的,是const且没有extern修饰的名称具有外部属性,但是在C++中却是内部链接属性。
在C里,寄存器变量的地址不能获取,但是在C++中,变量声明为register和没有任何存储类关键字修饰是没有什么区别的。(C++11之前)
C++中,不像C,变量不能声明为register。(C++17之后)
具有内部或外部链接属性的thread_local型变量的名称可以被不同的实例引用,依赖于代码是否在同一个或者不同的线程中执行。
关键字extern也可以指定语言链接属性和明确的模板实例声明,但是它不是存储类限定符(除非,声明被直接包含在语言链接指定中,在这种情况时,声明被像包含extern限定符一样对待)。
在C++语法中,关键字mutable是存储类限定符,尽管它不会影响存储周期或链接属性。
现在这段是不完整的,因为在同一个编译单元重新声明的规则。
存储类限定符,对于thread_local是个例外,不允许明确的指定和明确的实例。
template <class T> struct S {
thread_local static int tlm;
};
template <> thread_local int S<float>::tlm = 0; // "static" 没有出现在这里
7 关键字
auto, register, static, extern, thread_local
8举例
#include
#include
#include
#include
thread_local unsigned int rage = 1;
std::mutex cout_mutex;
void increase_rage(const std::string& thread_name)
{
++rage; // 锁外修改是没问题的;这是一个thread-local 变量
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << "Rage counter for " << thread_name << ": " << rage << '\n';
}
int main()
{
std::thread a(increase_rage, "a"), b(increase_rage, "b");
{
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << "Rage counter for main: " << rage << '\n';
}
a.join();
b.join();
}
可能的输出:
Rage counter for a: 2
Rage counter for main: 1
Rage counter for b: 2