文章目录
目录
[二、memcpy 在 C++ 里的 4 大致命问题](#二、memcpy 在 C++ 里的 4 大致命问题)
[1. 不能拷贝带有 指针 / 引用 / 动态内存 的对象](#1. 不能拷贝带有 指针 / 引用 / 动态内存 的对象)
[2. 不调用拷贝构造函数 / 赋值运算符](#2. 不调用拷贝构造函数 / 赋值运算符)
[3. 对象有虚函数时,memcpy 会直接破坏虚表指针](#3. 对象有虚函数时,memcpy 会直接破坏虚表指针)
[三、什么情况可以用 memcpy?](#三、什么情况可以用 memcpy?)
前言
推荐学完虚函数这章再回来看,不然有些概念理解不了
提示:以下是本篇文章正文内容
一、memcpy的作用
原型:
cpp
void* memcpy(void* dest, const void* src, size_t n);
作用 :把 src 开始的 n 个字节 ,无脑逐字节复制 到 dest
特点 :只拷贝内存,不调用任何构造函数、析构函数、赋值运算符
定位: memcpy是典型的浅拷贝
二、memcpy 在 C++ 里的 4 大致命问题
1. 不能拷贝带有 指针 / 引用 / 动态内存 的对象
例子1:
cpp
class string {
char* data; // 动态分配内存
};
string a = "hello";
string b;
memcpy(&b, &a, sizeof(a)); // ❌ 大错特错
结果:
a 和 b 指向同一块内存
析构时 重复释放同一块内存 → 程序崩溃
例子2:
cpp
int main()
{
bite::vector<bite::string> v;
v.push_back("1111");
v.push_back("2222");
v.push_back("3333");
return 0;
}
问题分析:
- memcpy 是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存
空间中 - 如果拷贝的是自定义类型的元素, memcpy 既高效又不会出错,但如果拷贝的是自定义类型
元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为 memcpy 的拷贝实际是浅
拷贝


由于扩容后,需要将原来的数据拷贝到新开辟的空间上,使用了memcpy后,💜紫色空间的的数据拷贝到💙蓝色空间,因此两个_str都指向了同一个空间"1111"

开辟新空间后,自然要释放旧空间,可是旧空间和新空间都指向同一块地址,因此释放完旧空间,新空间里的_str指向的内容就丢失了

2. 不调用拷贝构造函数 / 赋值运算符
C++ 对象的拷贝必须走自己的拷贝逻辑,而 memcpy 完全跳过:
不调用拷贝构造,不调用 operator=,不处理资源,不维护类内部状态
3. 对象有虚函数时,memcpy 会直接破坏虚表指针
cpp
#include <iostream>
#include <cstring> // memcpy
using namespace std;
class Base {
public:
virtual void show() {
cout << "Base::show()" << endl;
}
virtual ~Base() = default;
};
class Derived : public Base {
public:
void show() override {
cout << "Derived::show()" << endl;
}
};
int main() {
Derived d; // 真实类型 Derived
Base b; // 真实类型 Base
// 重点:用 memcpy 暴力拷贝对象内存
memcpy(&b, &d, sizeof(Base));
// 现在 b 的虚表指针已经被篡改成 Derived 的虚表指针了!
b.show(); // 这里会出现诡异行为:要么乱输出,要么直接崩
}
b 本来是 Base 类型,有自己的虚表指针 vptr, memcpy 把 d 的全部内存 拷给 b,包括它的 vptr
结果:b 的对象本体是 Base,虚表指针却是 Derived 的
这就叫对象切片 + 虚表错乱 ,C++ 标准里叫未定义行为(UB)
三、什么情况可以用 memcpy?
- 纯数据类型(int、float、结构体无指针)
- 无动态内存
- 无虚函数
- 无构造 / 析构逻辑
- 指针数组
cpp
Base* a[2] = {new Derived, new Derived};
Base* b[2];
memcpy(b, a, sizeof(a)); // ✅ 没问题
因为只复制地址,不碰对象本身
