Skip to content

内存操作基础设施实现分析

标准库提供了底层的内存操作函数,用于在未初始化的内存上构造/析构对象。本文基于 GCC 和 LLVM 的源码,分析内存操作基础设施的内部实现。


一、核心概念

1.1 什么是内存操作

内存操作是容器与内存分配器之间的桥梁:

容器操作 → 内存操作 → 分配器

例如 vector::push_back:
1. 分配器分配原始内存
2. 内存操作在原始内存上构造对象
3. 容器管理对象的生命周期
4. 析构时调用内存操作销毁对象

1.2 uninitialized_copy 的实现(源码分析)

cpp
// 源码路径:references/impl/gcc/libstdc++-v3/include/bits/stl_uninitialized.h

template<typename _InputIterator, typename _ForwardIterator>
_ForwardIterator
uninitialized_copy(_InputIterator __first, _InputIterator __last,
                   _ForwardIterator __result) {
    typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
    
    // 检查是否可以使用 memcpy/memmove
    if (__is_trivially_copyable<_ValueType>::value) {
        auto __n = std::distance(__first, __last);
        std::memmove(&*__result, &*__first, __n * sizeof(_ValueType));
        return __result + __n;
    }
    
    // 非平凡类型,逐个构造
    for (; __first != __last; ++__first, (void)++__result) {
        ::new (static_cast<void*>(std::addressof(*__result)))
            _ValueType(*__first);
    }
    return __result;
}

1.3 uninitialized_fill 的实现(源码分析)

cpp
// 源码路径:references/impl/gcc/libstdc++-v3/include/bits/stl_uninitialized.h

template<typename _ForwardIterator, typename _Tp>
void
uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last,
                   const _Tp& __x) {
    typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
    
    if (__is_trivially_copyable<_ValueType>::value) {
        auto __n = std::distance(__first, __last);
        std::fill_n(__first, __n, __x);
        return;
    }
    
    for (; __first != __last; ++__first) {
        ::new (static_cast<void*>(std::addressof(*__first)))
            _ValueType(__x);
    }
}

二、核心数据结构

2.1 uninitialized_copy

cpp
// GCC 的 uninitialized_copy
template<typename _InputIterator, typename _ForwardIterator>
_ForwardIterator
uninitialized_copy(_InputIterator __first, _InputIterator __last,
                   _ForwardIterator __result) {
    typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
    
    // 检查是否可以使用 memcpy/memmove
    if (__is_trivially_copyable<_ValueType>::value) {
        auto __n = std::distance(__first, __last);
        std::memmove(&*__result, &*__first, __n * sizeof(_ValueType));
        return __result + __n;
    }
    
    // 非平凡类型,逐个构造
    for (; __first != __last; ++__first, (void)++__result) {
        ::new (static_cast<void*>(std::addressof(*__result)))
            _ValueType(*__first);
    }
    return __result;
}

2.2 uninitialized_fill

cpp
// GCC 的 uninitialized_fill
template<typename _ForwardIterator, typename _Tp>
void
uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last,
                   const _Tp& __x) {
    typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
    
    if (__is_trivially_copyable<_ValueType>::value) {
        auto __n = std::distance(__first, __last);
        std::fill_n(__first, __n, __x);
        return;
    }
    
    for (; __first != __last; ++__first) {
        ::new (static_cast<void*>(std::addressof(*__first)))
            _ValueType(__x);
    }
}

三、GCC vs LLVM 差异对比

┌────────────────────────┬──────────────────────┬──────────────────────┐
│ 特性                    │ GCC (libstdc++)      │ LLVM (libc++)        │
├────────────────────────┼──────────────────────┼──────────────────────┤
│ uninitialized_copy     │ 完整                 │ 完整                 │
│ uninitialized_fill     │ 完整                 │ 完整                 │
│ uninitialized_move     │ C++17                │ C++17                │
│ construct_at           │ C++20                │ C++20                │
│ destroy_at             │ C++17                │ C++17                │
│ trivially_copyable 优化│ 支持                 │ 支持                 │
│ constexpr 支持         │ C++20                │ C++20                │
└────────────────────────┴──────────────────────┴──────────────────────┘

四、最佳实践

内存操作使用指南:

1. 优先使用 construct_at/destroy_at:
   · C++20 标准接口
   · 更安全

2. 使用 uninitialized_* 操作:
   · 在原始内存上构造对象
   · 适合自定义分配器

3. 注意异常安全:
   · 构造失败时销毁已构造的对象
   · 使用 RAII 管理生命周期

4. 优化平凡类型:
   · 使用 memcpy/memmove 替代逐个构造
   · 编译器会自动优化

延伸阅读

基于 MIT 许可发布