memset仅安全用于POD类型,按字节填充且不调用构造函数;对含虚函数、非平凡构造函数或std::string等成员的类使用会导致崩溃或UB;应优先选用std::fill、值初始化或容器方法。

memset 初始化数组时,必须确保目标类型是 POD 类型
memset 只按字节填充内存,不调用构造函数,因此不能用于含非平凡构造函数、虚函数、引用或私有成员的类对象数组。对 int、double、char 或纯 C 风格结构体(无构造函数、无虚表)才安全。
常见错误现象:memset 后对象成员看似清零,但实际调用其方法时崩溃——因为 vptr 也被覆写了;或者 std::string 数组被 memset 后析构时报 double-free。
- 安全场景:C 风格数组如
int arr[100]、struct Point { float x,y; } pts[50] - 不安全场景:
std::vector<int> vecs[10]、std::string strs[20]、自定义类class A { std::string s; } a[5] - 替代方案:优先用
std::fill、值初始化(int arr[10] = {})或容器的assign/resize
memset 第二个参数是 int,但只取低 8 位,别传 >255 的值
很多人误以为 memset(ptr, 1234, size) 能把每个 int 设为 1234 —— 实际上它把每个字节设为 1234 & 0xFF == 210,结果整个 int 变成 0xD2D2D2D2(小端下),完全不是预期值。
- 正确清零:
memset(arr, 0, sizeof(arr))—— 0 是唯一能安全扩展到任意整型宽度的值 - 想填非零值?用循环或
std::fill:std::fill(arr, arr + N, 42) - 对 char 数组填非零字节可以,比如
memset(buf, 'A', len)是合法的
sizeof 用错导致部分未初始化或越界
最常出错的是传错 size 参数:memset(arr, 0, N)(只清前 N 字节,而非 N 个元素),或对指针数组写 memset(ptr, 0, sizeof(ptr))(只清指针本身,非其所指)。
立即学习“C++免费学习笔记(深入)”;
- 固定大小数组:
int arr[100]; memset(arr, 0, sizeof(arr)); - 动态分配数组:
int* p = new int[100]; memset(p, 0, 100 * sizeof(int));—— 必须显式算字节数 - 二维数组注意:若
int mat[10][20],sizeof(mat)正确;但若int** mat,memset对它无效 - 结构体数组:用
sizeof(MyStruct) * count,别用sizeof(array_name)(若 array_name 是指针)
现代 C++ 中,多数情况该用更安全的替代方式
除非在性能敏感的底层代码(如图像处理、网络包填充)中明确需要字节级控制,否则 memset 属于“能不用就不用”的遗留接口。编译器对 = {}、std::fill、容器构造函数的优化已非常成熟,且语义清晰、类型安全。
- 栈数组初始化:
int arr[100] = {};(零初始化)或int arr[100]{1};(首元素为 1,其余为 0) - 堆数组:
std::unique_ptr<int[]> p(new int[100]());(括号触发零初始化) - STL 容器:
std::vector<int>(100, 42)或v.assign(100, 42) - 结构体初始化:
MyStruct s{};比memset(&s, 0, sizeof(s))更可读、可维护
真正容易被忽略的是:即使你确认当前类型是 POD,只要未来有人给结构体加一个 std::string 成员,memset 就立刻变成隐蔽的 UB。这种脆弱性,在多人协作或长期演进的项目里比性能损耗更值得警惕。


















