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

1|0参考内容

源码在github上

2|0std::allocator

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

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

3|0std::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>>>>; }

4|0std::ptrdiff_t

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

5|0std::reverse_iterator

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

6|0std::aligned_storage_t

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

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

7|0reinterpret_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 但这四字节不知道存的是什么 运行后可能会导致程序崩溃

8|0std::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()); }

9|0std::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()); }

10|0std::memcpy

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

11|0noreturn

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

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

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


__EOF__

本文作者铃灵狗的水墨书香
本文链接https://www.cnblogs.com/linglingdog/p/15874885.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   铃灵狗  阅读(130)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示