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));  // ✅ 没问题

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

相关推荐
lsx2024062 小时前
CSS 分组和嵌套
开发语言
zhangjw347 小时前
Java基础语法:变量、数据类型与运算符,从原理到实战
java·开发语言
yaoxin52112310 小时前
384. Java IO API - Java 文件复制工具:Copy 示例完整解析
java·开发语言·python
WBluuue10 小时前
数据结构与算法:康托展开、约瑟夫环、完美洗牌
c++·算法
NotFound48610 小时前
实战指南如何实现Java Web 拦截机制:Filter 与 Interceptor 深度分享
java·开发语言·前端
木子墨51611 小时前
LeetCode 热题 100 精讲 | 并查集篇:最长连续序列 · 岛屿数量 · 省份数量 · 冗余连接 · 等式方程的可满足性
数据结构·c++·算法·leetcode
Ava的硅谷新视界11 小时前
用了一天 Claude Opus 4.7,聊几点真实感受
开发语言·后端·编程
rabbit_pro11 小时前
Python调用onnx模型
开发语言·python
王老师青少年编程12 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【线性扫描贪心】:均分纸牌
c++·算法·编程·贪心·csp·信奥赛·均分纸牌