因为std::string内部含堆内存指针,memcpy仅复制指针值导致多对象共享同一堆内存,析构时双重释放而崩溃;正确方式是走构造/赋值语义,如用std::vector配合=、手动循环operator=或std::copy。

memcpy直接拷贝含std::string的结构体为什么崩溃
因为std::string内部通常包含指针(如指向堆上字符数据的_M_dataplus._M_p),其对象不是POD类型。用memcpy做位拷贝会复制指针值,但不会复制它指向的实际内存,导致多个std::string对象共享同一块堆内存;析构时多次释放同一地址,触发double free或访问已释放内存,程序崩溃。
常见错误现象:malloc(): double free detected in tcache 2、Segmentation fault (core dumped)、或在第二次delete附近断在__GI___libc_free。
正确复制含std::string结构体数组的三种方式
必须走构造/赋值语义,不能绕过std::string的管理逻辑:
- 用
std::vector代替裸数组,配合=或assign():自动调用每个元素的拷贝构造函数 - 手动循环调用
operator=(或std::copy):确保每个std::string执行深拷贝 - 如果必须用C风格数组,定义为
std::array<mystruct n></mystruct>,再用std::copy或逐个赋值
示例:
struct Person {
std::string name;
int age;
};
Person src[2] = {{"Alice", 30}, {"Bob", 25}};
Person dst[2];
// ❌ 危险!
// memcpy(dst, src, sizeof(dst));
// ✅ 安全(推荐)
for (int i = 0; i
<h3>什么时候<code>memcpy</code>才安全?</h3>
<p>仅当结构体满足以下全部条件时,<code>memcpy</code>才是可接受的:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill4025" title="C++ 算法竞赛自动化测试数据生成与校验框架"><img
src="https://img.php.cn/upload/skill/000/000/081/178988956499722.jpg" alt="C++ 算法竞赛自动化测试数据生成与校验框架" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill4025" title="C++ 算法竞赛自动化测试数据生成与校验框架" class="overflowclass">C++ 算法竞赛自动化测试数据生成与校验框架</a>
<p class="overflowclass">根据原题生成新题面、验证器及完整测试数据,自动套用 testlib 模板,用于用户要求生成测试数据时。</p>
</div>
<a rel="nofollow" href="/xiazai/skill4025" title="C++ 算法竞赛自动化测试数据生成与校验框架" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
- 是标准布局(standard-layout)且平凡可复制(trivially copyable)
- 所有成员都是POD类型(如
int、char[10]、float),不含std::string、std::vector、虚函数、引用、非平凡构造/析构函数 - 编译器未对齐填充引入不可控偏移(可通过
static_assert(std::is_trivially_copyable_v<t>)</t>验证)
验证方法:
static_assert(std::is_trivially_copyable_v<person>, "Person is not trivially copyable"); </person>
上面的Person会编译失败——这就是最直接的预警信号。
性能顾虑和替代方案
有人担心逐个赋值比memcpy慢,但实际影响有限:
-
std::string短字符串优化(SSO)下,小字符串不分配堆内存,拷贝只是复制固定长度缓冲区,开销极小 - 现代编译器对循环赋值常做向量化或内联优化,尤其配合
-O2 - 真有性能瓶颈时,应先用
perf或vtune确认热点是否真在这里,而不是预设memcpy更快
若结构体很大且确实需高性能批量复制,可考虑:把std::string改为const char* + 外部统一内存池,或改用absl::string_view(只存视图,不管理内存),但代价是语义变更和生命周期管理责任上移。
最易被忽略的一点:即使结构体当前没std::string,只要未来可能添加非POD成员,memcpy就埋下了隐性崩溃风险——别为省几行代码放弃类型安全。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










