C++中使用memcpy的拷贝问题

文章目录

目录

文章目录

前言

一、memcpy的作用

[二、memcpy 在 C++ 里的 4 大致命问题](#二、memcpy 在 C++ 里的 4 大致命问题)

[1. 不能拷贝带有 指针 / 引用 / 动态内存 的对象](#1. 不能拷贝带有 指针 / 引用 / 动态内存 的对象)

例子1:

例子2:

[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;
}

问题分析:

  1. memcpy 是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存
    空间中
  2. 如果拷贝的是自定义类型的元素, 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, memcpyd全部内存 拷给 b,包括它的 vptr

结果:b对象本体是 Base,虚表指针却是 Derived 的

这就叫对象切片 + 虚表错乱 ,C++ 标准里叫未定义行为(UB)


三、什么情况可以用 memcpy?

  1. 纯数据类型(int、float、结构体无指针)
  2. 无动态内存
  3. 无虚函数
  4. 无构造 / 析构逻辑
  5. 指针数组
cpp 复制代码
Base* a[2] = {new Derived, new Derived};
Base* b[2];
memcpy(b, a, sizeof(a));  // ✅ 没问题

因为只复制地址,不碰对象本身

相关推荐
邪修king28 分钟前
UE5 进阶篇第一弹:中期架构升级 —— 组件化开发与 Gameplay 框架实战
c++·游戏·架构·ue5
zhangfeng11331 小时前
openclaw skills 小龙虾技能 通讯仿真 matlab skill Simulink Agentic Toolkit,通过kimi找到,mcp通讯
开发语言·matlab·openclaw·通讯仿真
chao1898448 小时前
基于 SPEA2 的多目标优化算法 MATLAB 实现
开发语言·算法·matlab
赏金术士8 小时前
Kotlin 习题集 · 高级篇
android·开发语言·kotlin
楼兰公子9 小时前
buildroot 在编译rust时裁剪平台类型数量的方法
开发语言·后端·rust
知识领航员10 小时前
蘑兔AI音乐深度实测:功能拆解、实测表现与适用场景
java·c语言·c++·人工智能·python·算法·github
吴声子夜歌10 小时前
Go——并发编程
开发语言·后端·golang
ooseabiscuit10 小时前
Laravel4.x:现代PHP框架的奠基之作
java·开发语言·php
c1s2d3n4cs11 小时前
Qt模仿nlohmann::json进行序列化和反序列化
开发语言·qt·json
AiTop10011 小时前
Claude Code 推出 Agent View:命令行编程正式进入“多线程并发“时代
开发语言·人工智能·ai·aigc