• C++ 【轻量版STL】【造轮子】源码阅读学习笔记


    参考内容

    源码在github上

    std::allocator

    在内部生成一个allocator的实例 用来管理内存 完成对象的构造和析构

    template<typename T, std::size_t N = 16, typename Allocator = std::allocator<T>>
    

    std::conditional

    如果第一个参数判断为true 则使用类型1(第二个参数类型) 否则使用类型2(第三个参数类型)

    #include <type_traits>
    
    using  AAA = typename std::conditional<
            flag == true,
            bb::test_struct,
            bb::test_struct_2 >::type;
    

    连续判断:如果第一个判断为false 继续判断

    namespace Ubpa::details {
        template <std::size_t N>
        using static_vector_size_type
            = std::conditional_t<(N < std::numeric_limits<uint8_t>::max()), std::uint8_t,
            std::conditional_t<(N < std::numeric_limits<uint16_t>::max()), std::uint16_t,
            std::conditional_t<(N < std::numeric_limits<uint32_t>::max()), std::uint32_t,
            std::conditional_t<(N < std::numeric_limits<uint64_t>::max()), std::uint64_t,
            std::size_t>>>>;
    }
    

    std::ptrdiff_t

    计算两个指针地址的差
    计算公式:地址的差值 / 指针所指类型

    std::reverse_iterator

    反向迭代器 从容器的最后一个元素开始遍历 ++是查看前一个元素 与正常的迭代器是相反的

    std::aligned_storage_t

    std::aligned_storage_t<sizeof(T)* N, alignof(T)> m_storage:创建一块大小为T * N字节的内存空间 同时内存对齐要求为T
    这个函数保证了内存对齐
    内存对齐的好处:

    1. 提高了代码的可移植性 有些硬件无法访问非对齐的内存
    2. 大大提高了CPU的速度 如果内存对齐 CPU将内存块的数据写入寄存器时可以一块一块写入 否则只能先写入再剔除 非常影响效率

    reinterpret_cast

    按字节拷贝的类型转换 常用于相似类型的指针或者引用之间相互转换 风险大

    #include <iostream>
    using namespace std;
    class A
    {
    public:
        int i;
        int j;
        A(int n):i(n),j(n) { }
    };
    int main()
    {
        A a(100);
        int &r = reinterpret_cast<int&>(a); //强行让 r 引用 a
        r = 200;  //把 a.i 变成了 200
        cout << a.i << "," << a.j << endl;  // 输出 200,100
        int n = 300;
        A *pa = reinterpret_cast<A*> ( & n); //强行让 pa 指向 n
        pa->i = 400;  // n 变成 400
        pa->j = 500;  //此条语句不安全,很可能导致程序崩溃 【*】
        cout << n << endl;  // 输出 400
    

    【*】:编译器认为j的值为n后面的四字节中 于是编译器将向这四字节中写入500 但这四字节不知道存的是什么 运行后可能会导致程序崩溃

    std::uninitialized_value_construct等

    std::uninitialized_value_construct//初始化内存
    std::uninitialized_value_construct(begin(), end())//初始化从begin到end大小的内存
    //其中begin和end返回的都是指针
    
    std::uninitialized_fill(begin(), end(), value)//大概是初始化内存后用value去填充
    
    std::uninitialized_copy(other.begin(), other.end(), begin())//内存复制
    
    std::uninitialized_move(other.begin(), other.end(), begin())//内存move 消除原有内存
    

    参数列表初始化

    std::initializer_list<value_type> ilist
    

    实现了vector可以直接指定初始化的数值 而无需指定初始化vector的大小:

    std::vector<int> a = {1, 2, 3};
    

    自己设计vector时使用这种功能:

    static_vector(std::initializer_list<value_type> ilist) : m_size{ static_cast<size_type>(ilist.size()) } {
                assert(ilist.size() <= N);
                std::uninitialized_copy(ilist.begin(), ilist.end(), begin());
            }
    

    std::is_trivially_copy_assignable_v

    std::is_trivially_copy_assignable_v<value_type> 判断参数是否是具有普通复制赋值运算符的类
    std::is_trivially_copy_constructible_v<value_type> 判断参数是否是具有普通复制构造函数的类
    is_trivially_destructible_v 判断T是否具有析构函数
    这里大概可能是判断value_type类型是否可以计算sizeof?可能和memcpy的底层实现有关吧
    判断为否的话直接使用内存复制的方式完成拷贝。

    if constexpr (std::is_trivially_copy_assignable_v<value_type> && std::is_trivially_copy_constructible_v<value_type>) {
                            std::memcpy(&m_storage, &rhs.m_storage, rhs.m_size * sizeof(value_type));
                        }
                        else {
                            std::copy(rhs.begin(), rhs.begin() + m_size, begin());
                            std::uninitialized_copy(rhs.begin() + m_size, rhs.end(), end());
                        }
    

    std::memcpy

    void *memcpy(void*dest, const void *src, size_t n)
    //由src指向地址为起始地址的连续n个字节的数据复制到以destin指向地址为起始地址的空间内。
    

    noreturn

    告诉编译器这个函数用不返回 帮助编译器优化
    例子中这个函数用于当发生数组越界访问时抛出异常 所以它不用任何的返回值
    该函数要么总是抛出异常 要么永不停止

    [[noreturn]] void throw_out_of_range() const { throw std::out_of_range("invalid static_vector subscript"); }
    

    个人理解和void的区别:
    void函数在函数调用之后 编译器会做一些清理工作 比如调整栈指针等 noreturn告诉编译器可以省略清理工作的环节 可以省去很多无关紧要的代码

  • 相关阅读:
    docker--docker介绍
    docker--虚拟化
    高级运维工程师的打怪升级之路
    mysql常用函数
    CentOS 7 下使用 Firewall
    51nod 1094 和为k的连续区间(map+前缀和)
    51nod 1092 回文字符串(dp)
    51nod 1062 序列中最大的数(打表预处理)
    51nod 1284 2 3 5 7的倍数(容斥原理+反面思考)
    51nod 1347 旋转字符串(思维好题)
  • 原文地址:https://www.cnblogs.com/linglingdog/p/15874885.html
Copyright © 2020-2023  润新知