You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改C++ vector返回引用后Valgrind报错及关联崩溃分析

问题背景

尝试通过引用修改std::vector,期望在引用生命周期内,通过引用修改始终有效(即引用指向的对象不会被释放),但出现了内存错误。

最小可复现代码

#include <vector>
class B {
public:
  B() { m_b = 1; }
  int &getInt() { return m_b; }

private:
  int m_b;
};
class A {
public:
  B &getB() {
    m_vec.push_back(B());
    return m_vec.back();
  }
  std::vector<B> getVec() { return m_vec; }

private:
  std::vector<B> m_vec;
};
int main() {
  A a;
  B &b1 = a.getB();
  int i = b1.getInt();
  B &b2 = a.getB();
  b1 = B();

  return 0;
}

Valgrind检测输出

==22925== Memcheck, a memory error detector
==22925== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==22925== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==22925== Command: ./test
==22925== 
==22925== Invalid write of size 4
==22925==    at 0x1092B5: main (test.cpp:27)
==22925==  Address 0x4deec80 is 0 bytes inside a block of size 4 free'd
==22925==    by 0x484BB6F: operator delete(void*, unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==22925==    by 0x109E28: __gnu_cxx::new_allocator<B>::deallocate(B*, unsigned long) (new_allocator.h:145)
==22925==    by 0x109B6F: std::allocator_traits<std::allocator<B> >::deallocate(std::allocator<B>&, B*, unsigned long) (alloc_traits.h:496)
==22925==    by 0x1098D9: std::_Vector_base<B, std::allocator<B> >::_M_deallocate(B*, unsigned long) (stl_vector.h:354)
==22925==    by 0x109A97: void std::vector<B, std::allocator<B> >::_M_realloc_insert<B>(__gnu_cxx::__normal_iterator<B*, std::vector<B, std::allocator<B> > >, B&&) (vector.tcc:500)
==22925==    by 0x1096E5: B& std::vector<B, std::allocator<B> >::emplace_back<B>(B&&) (vector.tcc:121)
==22925==    by 0x1094ED: std::vector<B, std::allocator<B> >::push_back(B&&) (stl_vector.h:1204)
==22925==    by 0x1093F4: A::getB() (test.cpp:14)
==22925==    by 0x10929D: main (test.cpp:26)
==22925==  Block was alloc'd at
==22925==    at 0x4849013: operator new(unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==22925==    by 0x109FED: __gnu_cxx::new_allocator<B>::allocate(unsigned long, void const*) (new_allocator.h:127)
==22925==    by 0x109EAC: std::allocator_traits<std::allocator<B> >::allocate(std::allocator<B>&, unsigned long) (alloc_traits.h:464)
==22925==    by 0x109D65: std::_Vector_base<B, std::allocator<B> >::_M_allocate(unsigned long) (stl_vector.h:346)
==22925==    by 0x1099C0: void std::vector<B, std::allocator<B> >::_M_realloc_insert<B>(__gnu_cxx::__normal_iterator<B*, std::vector<B, std::allocator<B> > >, B&&) (vector.tcc:440)
==22925==    by 0x1096E5: B& std::vector<B, std::allocator<B> >::emplace_back<B>(B&&) (vector.tcc:121)
==22925==    by 0x1094ED: std::vector<B, std::allocator<B> >::push_back(B&&) (stl_vector.h:1204)
==22925==    by 0x1093F4: A::getB() (test.cpp:14)
==22925==    by 0x10927C: main (test.cpp:24)
==22925== 
==22925== 
==22925== HEAP SUMMARY:
==22925==     in use at exit: 0 bytes in 0 blocks
==22925==   total heap usage: 3 allocs, 3 frees, 72,716 bytes allocated
==22925== 
==22925== All heap blocks were freed -- no leaks are possible
==22925== 
==22925== For lists of detected and suppressed errors, rerun with: -s
==22925== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

疑问

  1. 为何Valgrind会出现该无效写入错误?
  2. 原程序运行数毫秒后崩溃并打印malloc(): unsorted double linked list corrupted,该崩溃是否与该内存bug相关?

问题解答

1. Valgrind无效写入错误的原因

std::vector底层依赖连续内存缓冲区。当调用push_back时,如果当前缓冲区剩余空间不足以容纳新元素,vector会重新分配一块更大的内存,将旧缓冲区的元素拷贝/移动到新内存后释放旧缓冲区。

在你的代码流程里:

  • 第一次调用a.getB(),vector为空,分配内存插入第一个B对象,返回该对象的引用b1。
  • 第二次调用a.getB()时,vector初始容量通常为1,已满触发重新分配:旧内存被释放,新内存分配并存放两个B对象。此时b1指向的是已经被释放的旧内存地址。
  • 最后执行b1 = B();,本质是往已释放的内存地址写入数据,这就是Valgrind检测到的无效写入。

2. 崩溃与内存bug的关系

是的,崩溃完全由该内存bug导致。

往已释放的内存写入数据会破坏malloc维护的堆内存管理结构(比如用于管理空闲块的双链表节点信息)。后续malloc/free操作尝试访问这些被破坏的结构时,就会触发malloc(): unsorted double linked list corrupted这类错误,直接导致程序崩溃。这种堆内存损坏的表现可能延迟出现,但根源就是之前的无效写入操作。


内容的提问来源于stack exchange,提问作者user1006274

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 09:42:02