前段时间查到这方面的东西,看这里讲的不错,就翻译了,第一次尝试 :)
原文地址:http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=28
内存管理
在 C++ 中,一种存储类别 (storage class) 定义了某个标志符的内存属性。同样它也决定了一个对象的内存生存期 (storage duration): 自动存储生存期 (automatic storage duration) , 线程存储生存期 (thread storage duration) ,静态存储生存期 (static storage duration) , 和空闲内存 (free store) 。每种存储类别规定了不同的内存使用限制,并表示不同的初始化,生命生存期,作用域和链接语义。决定一个标志符存储生存期的因素有:
1> 出现在标志符声明前面的存储类型说明符 (e.g., static, thread_local, extern, register) 。
2> 上下文 ( 比如说,定义在命名空间里的用户定义类型以及函数的参数 )
3> 标识符类型 ( 一个函数,一个数据成员等等 ) 。
下面的章节将解释不同 C++ 存储生存期的区别,讨论他们的使用并列举他们在 C ,旧标准 C++ 和 C++09 之间的区别。
自动存储
内存生存期是对象的一个属性,它定义了这个对象在内存中的最小生存时间。内存生存期由创建对象的构造函数决定,包括存储类型标志符。最常见的存储生存期是自动存储生存期。 因为在堆栈上分配的对象是自动分配和自动释放的,所以具有自动存储生存期。下面的对象具有自动存储属性:
1> 没有被显式声明为 static, extern 或者 thread_local 的局部变量
2> 声明带有 auto 存储说明符的局部变量 ( 适用 C 的所有版本和除了 C++09 之外的 C++ 版本 )
3> 声明带有 register 存储说明符的对象
4> 函数参数
5> 临时对象
存储类型标志符
不要混淆了存储生存期与存储类型标志符。 C++09 存储类型标志符有:
1> register
2> static
3> thread_local
4> extern
5> mutable
与 C++09 之前的存储类型说明符列表有点不同:
1> register
2> static
3> auto
4> extern
5> mutable
在 C 语言中,存储类型说明符有:
1> register
2> static
3> auto
4> extern
自动存储生存期
下面的代码包括了自动存储生存期类型的不同声明,对象和变量。
void f(const std::string & s); //storage type of the string object is determined by the caller void g(register int n); //function parameter and register, hence automatic int main() { int n; // automatic because local, non-static, non-extern and non thread_local std::string s; // ditto register int i; // register implies automatic auto double d; // automatic. Valid in all C++ dialects but C++09 g(n); //passing a copy of n; the copy is automatic f(std::string temp()); // a temporary has automatic storage }
自动存储生存期类型的对象,简称自动对象,是在进入一个块或一个函数时自动创建的。当程序退出他们所声明的块或者函数时,他们就会被销毁,并且其内存会被自动回收。因此,在一个函数或者块的入口处会创建其自动对象。自动对象和非类对象的默认值都是不确定的。自动对象不可链接,不能从不同的 编译单元 (translation unit) 引用自动对象,并且他们只能在声明的作用域内可见。
C++09 标准不再将 auto 视为一个内存类型标志符。因此,在 C++09 的代码里不能使用 auto 来指定自动内存生存期。因而 C++09 中自动存储生存期隐藏于上下文中。 auto 关键字在 C++09 中仍然存在,但是意义已经改变,所以程序员必须小心:使用了 auto 作为存储类型的旧版 C 和 C++ 代码编译会出错。
Register 存储类型标志符
Register 存储类型标志符仅被用来修饰块中声明的对象或者函数参数。声明一个带有 register 标志符的对象暗示存取此对象会尽可能的快。例如,在一个双重循环里声明一个 register 类型的计数器可能会被存储在 CPU 的 register 里而不是内存里。类似地,一个声明成 register 类型的类对象可能会被存储到 cache 里以便快速存取。这种 register 请求的有效性从某种程度上与实现相关。现在, C 或者 C++ 里已经几乎不使用 register 类型了。大部分编译器不会理会用户的 register 变量和对象的请求。相反,编译器会自动做出 register 类型的选择。 ISO C 规定用户不能获得 register 对象的地址。在 C++ 中可以这么做,但是这样会使 register 类型请求失效(对象将被存到内存中)。在其他所有方面(如初始化,生命生存期, 作用域)带有 register 存储类型的对象和自动对象具有同样的语义。
Mutable 存储类型标志符
Mutable 标志符修饰一个 const 类数据成员会使其 const 属性无效并且会允许更改 mutable 类型的类数据成员,尽管对象中其余的成员都是 const 类型的。换句话说,就算是 const 对象,其 mutable 成员通常是可以改变的。
struct S { mutable int x; int y; }; const S s; s.x=0; //OK, mutable member in a const object s.y=0; //error, y is a member of a const object
mutable 标志符只能被用在类数据成员的名字前,并且不能和 const 或者 static 同时使用,也不能用来修饰引用变量。
例如
class C { mutable const int* p; // OK, the pointer is mutable, int is const mutable int* const q; // ill-formed mutable int &r; //error, references cannot be mutable };
成员 p 的声明中, mutable 标志符修饰指针,而 const 标志符修饰被指针指向的 int 数据。反之, q 的声明则是无效的,因为指针被同时声明为 const 和 mutable 了。类似地,引用变量 r 的声明是无效的,因为引用变量不可变。
静态存储生存期和线程存储生存期
全局对象和在 namespace 作用域中的对象,类的静态数据成员,以及函数中驻留在静态存储区的局部静态对象。一个带有静态存储生存期属性的对象在程序的整个执行期间都会驻留在相同的内存中。每一个这种对象在程序的生命生存期内只创建一次。静态数据默认全部被初始化为 0 。带有一个自定义构造函数或者一个显式动态初始器的静态对象都将经历一个二次初始化阶段,我们称之为动态初始化。
在一个函数中声明的对象,其作用域就被限制在那个函数中。下面的例子中有些静态存储的对象:
int num=0; //global variables have static storage extern int x; //also global, defined in a separate translation unit int func() { static int calls; //local static. initialized to 0 by default x=calls; return ++calls; } class C { private: static bool b; }; namespace NS { std::string str; //str has static storage }
extern 存储类型标志符
extern 标志符只能用来修饰对象和函数。 extern 标志符不能被用在类成员或者函数参数的声明中。声明成 extern 的标识符具有外部链接性,意味着他们在同一个程序的所有 编译单元中都是可见的。
在 namespace 作用域中声明的不带存储类型标志符的名称具有外部链接性,除非其由于被声明过而已经具有内部链接性,或者被声明为 const 类型。被声明为 const 类型的对象和未被显式声明为 extern 的对象具有内部链接性,意味着他们只在他们所声明的 编译单元内可见。
注意 extern 关键字还可以用在别处,他也可以被用在模板的实现初始化和链接标识中,但是此时 extern 已经不再是一个存储类型标志符。
thread_local 存储生存期
thread_local 标志符表明其修饰的对象或者引用具有线程存储生存期。 thread_local 只能用来修饰命名空间中的对象或者引用的名字,以及块作用域中已经被指定为 static 存储类型的对象和引用。 thread_local 存储类型是 C++09 中的新特征。在此不详细讨论。