TinySTL 之建构和结构工具 stl_construct

2022-5-26 大BUG阅读数:2019评论数:15   C++ 泛型编程 小项目
提示:此篇文章需要了解 C++ 泛型编程的一些概念才能看得懂本文章。

STL 有 6 大部件,其中 allocator 对应的就是函数中的内存分配与对象建立,而为了减少代码量,allocator 把这部分的工作剥离开放到了 stl_construct.h 中,使用placement new函数实现内存的申请。 关于 C++ 内存申请的三种方式:new, operator new 和 placement new,可以查看 这篇博客,里面较为详细地讲解了三种方式的区别,并且给了相应的的 例子。

注意,这里可能会用到后面使用到的例子,例如 ForwardIter,表示的是容器的迭代器,不过都很好理解。

成员类型

成员函数

construct 成员函数

函数 定义
template <typename T>
void construct(T *ptr)
构造函数1
template <typename T1, class T2>void
void construct(T1 *ptr, const T2 &&value);
构造函数2
template <typename T1, class... Args>
void construct(T *ptr, Args&&... args);
构造函数3
template <typename T>
void destroy(T *ptr);
析构函数1
template <typename ForwardIterator>
void destroy(ForwardIterator first, ForwardIterator, last);
释放分配的内存
template <typename T>
void destroy_one(T*, std::true_type);
释放内存 ptr
template <typename T>
void destroy_one(T*, std::false_type);
释放内存 ptr
template <typename ForwardIter>
void destroy_cat(ForwardIter first, ForwardIter last, std::true_type);
循环释放容器内存
template <typename ForwardIter>
void destroy_cat(ForwardIter first, ForwardIter last, std::false_type);
循环释放容器内存

源码

关于源码部分的实现,主要借鉴于 STL 源码剖析这本书,并且 C++11 的一些新特性实现,这里涉及到了不定参数模板 typename<... Args>std::move,完美转发等概念,需要提前掌握一下。

   
#ifndef TINYSTL_ALLOCATOR_H_
#define TINYSTL_ALLOCATOR_H_

// 这个头文件包含两个函数 construct,destroy
// construct : 负责对象的构造
// destroy   : 负责对象的析构

#include <new>

#include "type_traits.h"
#include "iterator.h"

namespace TinySTL
{

// construct 构造对象
    
// 使用placement new在分配的内存ptr初始化对象,构造函数T()
template <typename T>
void construct(T* ptr)
{
    ::new ((void*)ptr) T();                           
}

// 使用placement new在分配的内存ptr初始化对象,构造函数T(value);
template <typename T1, typename T2>
void construct(T1* ptr, const T2& value)
{
    ::new ((void*)ptr) T1(value);                    
}

template <typename T, typename... Args>
void construct(T* ptr, Args&&... args)
{
    ::new ((void*)ptr) T(TinySTL::forward(args)...);     //  使用forward实现不定参数的完美转发
}

// destroy 将对象析构

template <typename T>
void destroy_one(T*, std::true_type) {}

// 调用了析构函数 ~T(),但是 pointer 所在内存并没有释放
// 需要分配器的 operator delete(ptr) 释放
template <typename T>
void destroy_one(T* pointer, std::false_type)
{
    if (pointer != nullptr)
    {
        pointer->~T();                                       
    }
}

template <typename ForwardIter>
void destroy_cat(ForwardIter , ForwardIter , std::true_type) {}

template <typename ForwardIter>
void destroy_cat(ForwardIter first, ForwardIter last, std::false_type)
{
    for (; first != last; ++first)
        destroy(&*first);
}

template <typename T>
void destroy(T* pointer)
{
    destroy_one(pointer, std::is_trivially_destructible{});
}

template <typename ForwardIter>
void destroy(ForwardIter first, ForwardIter last)
{
    destroy_cat(first, last, std::is_trivially_destructible<
            typename iterator_traits<ForwardIter>::value_type>{});
}

} // namespace TinySTL

#endif // !TINYSTL_ALLOCATOR_H_

                        

测试

这部分必须配合后面的 stl_allocator 一起测试,因为需要 allocator 来申请和释放内存。