3.空类的sizeof

Q1:关于继承类大小与空类大小

• 一个空类,无基类,其大小为1 :对空类而言,其中含有编译器安插进去的一个 char ,这使的这个类的两个对象得以在内存中配置独一无二的地址

• 一个空类,继承自一个空基类,其大小为1 :其基类的大小占1个字节,而其本身并不占空间,通过其基类子对象的独一无二性来体现其本身的独一无二性

• 一个空类,继承自一个空的虚基类,其大小分两种情况:

1) 提供优化处理,其大小为4:空的虚基类被看做派生类最开头的一部分,则派生类本身并不含数据,通过虚基类来进行区分,含有4字节的指针指向虚基类的表

2) 不提供优化处理,其大小为8 :空的虚基类不看作派生类的一部分,则派生类处理包含指向虚基类表的4字节之外,还需要标识其自身的1字节,共5字节,为了对齐需求,将对其进行补齐,因此,将为8字节

Eg: 以下情况下,各个类的大小

    class X{};
    class Y : public virtual X{};
    class Z : public virtual X{};
    class W : public Y, public Z{};

继承关系如下图:
这里写图片描述

1.不提供优化处理

• sizeof X 的结果为 1
• sizeof Y 的结果为 8
• sizeof Z 的结果为 8 
• sizeof A 的结果为 12

分析:
• Y 的大小,如图:
这里写图片描述

• 此时的 A 的大小为:

□ 被大家共享的唯一一个类 X 的实例大小 1字节

□ 基类 Y 的大小减去因虚基类 X 而配置的大小(4字节的指针)结果是4字节。Z 所占大小也为 4 字节

□ 类 A 自身由非虚基类 Y 与 Z 标识,故 Y 所占大小为0

□ 此时总和为9字节,因对齐需要补充到12字节

2.提供优化处理

• sizeof X 的结果为 1
• sizeof Y 的结果为 4
• sizeof Z 的结果为 4
• sizeof A 的结果为 8

分析:
• Y的大小,如图:
这里写图片描述

• 此时 A 的大小为:

○ 此时类 X 的实例的 1字节将不存在,(作为类 Y 与类 Z的一部分了)

○ 类 Y 的大小与类 Z 的大小,均为 4字节

○ 类 A 自身的大小由非虚基类 Y , Z标识,所占为0

○ 总和大小为 8 字节,不需要补齐
<think>好的,我现在需要解释一下C++中`.size()`和`sizeof`的区别。首先,我得回忆一下这两个各自的作用和用法。 用户可能是在学习C++的时候遇到了这两个概念,容易混淆。他们可能在不同的代码中看到过这两种用法,但不太清楚什么时候该用哪一个。我需要明确这两个关键点的区别,避免他们以后犯错。 首先,`.size()`是成员函数,通常属于STL容器,比如`std::vector`、`std::string`、`std::list`等。而`sizeof`是C++的一个运算符,用于获取对象或类型的内存大小,以字节为单位。这点我记得没错,但需要更详细地展开。 比如,对于`std::string str = "hello";`,`str.size()`返回的是字符串的长度,这里是5。而`sizeof(str)`则会返回`std::string`这个对象在内存中的大小,这可能包括内部缓冲区指针、大小等成员变量,所以会比5大很多,比如在64位系统上可能是32字节之类的。这时候用户可能会疑惑为什么结果不同。 然后,`sizeof`在编译时就已经确定结果,它不计算动态分配的内存。例如,`int arr[10];`,`sizeof(arr)`会是`10 * sizeof(int)`,而如果有一个指针`int* p = new int[10];`,`sizeof(p)`只是指针的大小,通常是4或8字节,而不是数组的大小。这时候用户可能会误解`sizeof`可以获取动态数组的长度,但其实不行。 接下来,要区分`.size()`是动态获取元素数量,而`sizeof`是静态类型大小。比如,对于`std::vector<int> vec(10);`,`vec.size()`是10,而`sizeof(vec)`则是vector对象本身的大小,包括内部指针、容量等,而不是元素占用的总内存。 还要注意,`.size()`是成员函数,所以调用时需要对象实例,而`sizeof`可以作用于类型或实例。例如,`sizeof(int)`是4(假设int是4字节),而`sizeof(vec)`是对象的大小。 可能用户还会混淆`sizeof`对于字符串字面量的情况,比如`sizeof("hello")`,这里会包括空终止符,所以是6字节,而`strlen("hello")`是5,`std::string`的size()也是5。这时候需要指出`sizeof`处理的是内存占用,而size()或strlen()处理的是逻辑长度。 另外,用户可能会遇到在数组中使用sizeof的情况,比如`int arr[] = {1,2,3};`,`sizeof(arr)/sizeof(arr[0])`可以得到元素个数,但这种方法在数组作为参数传递到函数时会失效,因为数组会退化为指针。这时候应该用`std::array`或者`std::vector`的size()方法。 总结的时候,需要强调`.size()`用于STL容器,返回元素数量;`sizeof`是运算符,返回对象或类型的内存大小。一个在运行时计算,一个在编译时确定,并且应用场景不同。 可能还需要举一些例子来帮助理解,比如不同的数据结构和不同类型的sizeof结果对比。同时,提醒用户常见的误用情况,比如用sizeof来获取动态数组的长度,或者混淆字符串的长度和对象大小。 最后,要确保语言通俗易懂,避免使用过于专业的术语,但又要准确无误。可能还需要提到,在C++17中引入了`std::size()`函数,可以用于数组和容器,但那是另一个话题了。不过用户的问题主要是关于成员函数.size和运算符sizeof,所以应该集中在两者的区别上。</think>### 一、核心区别总结 `.size()` 和 `sizeof` 是 C++ 中 **完全不同的两个概念**,主要区别如下: | **特性** | **`.size()`** | **`sizeof`** | |------------------|----------------------------------------------|---------------------------------------------| | **本质** | 成员函数(属于容器或字符串对象) | 运算符(编译器关键字) | | **作用对象** | STL 容器(如 `vector`, `string`, `list` 等) | 任何类型或对象(包括基础类型、结构体等) | | **返回值含义** | 容器中元素的数量 | 对象/类型占用的内存字节数 | | **计算时机** | 运行时动态计算 | 编译时静态确定 | | **依赖动态内存** | 反映动态分配的元素数量 | 不统计动态内存(只计算对象本身的固定大小) | --- ### 二、具体场景分析 #### 1. **对 `std::string` 的操作** ```cpp #include <iostream> #include <string> int main() { std::string str = "hello"; // .size() 返回字符串长度(元素数量) std::cout << str.size(); // 输出 5 // sizeof 返回 std::string 对象本身的内存大小 std::cout << sizeof(str); // 输出 32(64位系统下,包含内部缓冲指针等信息) return 0; } ``` #### 2. **对数组的操作** ```cpp #include <iostream> int main() { int arr[10] = {0}; int* dynamic_arr = new int[10]; // sizeof 返回整个数组占用的字节数 std::cout << sizeof(arr); // 输出 40(假设 int 占4字节,10*4=40) // sizeof 对指针返回指针本身的大小(与数组内容无关) std::cout << sizeof(dynamic_arr); // 输出 8(64位系统下指针大小) delete[] dynamic_arr; return 0; } ``` #### 3. **对 STL 容器的操作** ```cpp #include <iostream> #include <vector> int main() { std::vector<int> vec(100); // 包含100个int元素 // .size() 返回容器内元素数量 std::cout << vec.size(); // 输出 100 // sizeof 返回 vector 对象本身的内存大小(固定值,与元素数量无关) std::cout << sizeof(vec); // 输出 24(64位系统下,包含指针、容量等成员) return 0; } ``` --- ### 三、常见误区与注意事项 #### 1. **错误用法示例** ```cpp // 错误:试图用 sizeof 获取动态数组长度 int* p = new int[100]; int len = sizeof(p) / sizeof(int); // len = 2(64位系统下,8/4=2) // 正确做法:只能手动记录长度或使用容器 std::vector<int> vec(100); int len = vec.size(); // len = 100 ``` #### 2. **字符串字面量的特殊行为** ```cpp const char* str = "hello"; std::cout << strlen(str); // 输出 5(实际字符数) std::cout << sizeof(str); // 输出 8(指针大小) std::cout << sizeof("hello"); // 输出 6(包含 &#39;\0&#39; 终止符,占6字节) ``` --- ### 四、总结对比表 | **场景** | **`.size()`** | **`sizeof`** | |------------------------------|------------------------|-----------------------------------| | 获取 `std::string` 字符数 | ✅ 正确(如 `str.size()`) | ❌ 错误(返回对象内存大小) | | 获取数组元素数量(静态数组) | ❌ 不可用 | ✅ 正确(需配合 `sizeof(arr)/sizeof(arr[0])`) | | 获取动态数组长度 | ❌ 不可用 | ❌ 错误(只能得到指针大小) | | 获取容器元素数量 | ✅ 正确(如 `vec.size()`) | ❌ 错误(返回容器对象内存大小) | | 计算类型内存占用 | ❌ 不可用 | ✅ 正确(如 `sizeof(int)`) | --- ### 五、扩展知识 C++17 引入了 **`std::size()`** 函数,可统一处理容器和原生数组: ```cpp #include <iterator> int arr[] = {1,2,3}; std::vector<int> vec{4,5,6}; std::cout << std::size(arr); // 输出 3 std::cout << std::size(vec); // 输出 3 ``` 但本质上,它仍然是通过编译时模板特化实现的,与 `.size()` 的运行时特性不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值