C++类的成员变量是在堆区还是在栈区

C++内存分配基础

  • 在理解C++类的成员变量存储位置之前,我们先要了解C++中的几种主要内存区域
    • 栈区(Stack): 栈区内存由编译器自动分配和释放,存储函数的局部变量,参数等。栈区内存具有生命周期短,分配效率高的特点
    • 堆区(Heap): 堆区内存由程序员手动分配和释放(使用new和delete)。堆区内存的生命周期由程序员控制,适合存储需要长时间存在的数据
    • 静态存储区(Static Storage): 该区域存储静态数据成员和全局变量,内存分配在程序开始时进行,直到程序结束时才释放
    • 代码区和常量区: 存储程序代码和常量数据

类的成员变量存储位置

  • 类的成员变量的存储位置取决于类的实例(对象)如何创建。主要有以下几种情况
  1. 栈上分配的对象
    • 当一个对象在栈上分配时,成员变量也存储在栈上
  2. 堆上分配的对象
    • 当使用new关键字动态分配一个对象时,对象和其成员变量会存储在堆上。
  3. 静态存储区的对象
    • 如果一个对象是全局变量或静态变量,那么它会被分配在静态存储区。
    • 这些对象的内存在程序开始时分配,并且在程序运行期间一直存在,直到程序结束时才会释放。因此,静态对象和全局对象的成员变量存储在静态存储区中。

C __BEGIN_DECLS 是什么

__BEGIN_DECLS__END_DECLS 是在C语言和C++代码混合时使用的宏。它们用于确保 C 头文件在被 C++ 编译器编译时能够正确处理 C 函数原型。

当在 C++ 环境中包含 C 头文件时,需要用 extern "C" 来告诉 C++ 编译器这些声明是 C 语言的,以便正确处理名字修饰(name mangling)。__BEGIN_DECLS__END_DECLS 宏正是为了简化这一过程而设计的。

1
2
3
4
5
6
7
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif

这段代码的含义是:

  • 如果编译器是 C++ 编译器 (__cplusplus 被定义),则 __BEGIN_DECLS 被定义为 extern "C" {__END_DECLS 被定义为 }
  • 如果编译器是 C 编译器,则这两个宏都定义为空。

使用这些宏可以这样写一个头文件:

1
2
3
4
5
6
7
8
9
10
#ifndef MY_HEADER_H
#define MY_HEADER_H

__BEGIN_DECLS

void my_function();

__END_DECLS

#endif // MY_HEADER_H

当这个头文件在 C++ 代码中被包含时,my_function 的声明会被包含在 extern "C" 块中,从而避免了 C++ 名字修饰问题。在 C 代码中,宏会被定义为空,所以对代码没有影响。