
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
- 系列文章目录
- 前言
- 一、重写STL建议
- 二、c++新特性keyword(言简意赅)
- 1.explicit和implicit
- 2.noexcept
- 三、type_trait
- 四、construction
- 五、util
- 1 move和forward
- 2 pair
前言
帮助c++初学者更加友好的了解c++STL源码剖析
提示:以下是本篇文章正文内容,下面案例可供参考
STL可分为容器(containers)、迭代器(iterators)、空间配置器(allocator)、配接器(adapters)、算法(algorithms)、仿函数(functors)六个部分。type_trait->construction->util
二、c++新特性keyword(言简意赅) 1.explicit和implicit首先在了解keyword之前你得先了解隐式转换(implicit conversion)和显示转换(explicit conversion)
int a=1;//编译器帮你做的转换-explicit
float b =(float)a//强制转换-implicit
然后让我们来了解 keyword
explicit:在C++语言中,类中的构造函数如果只含有一个参数,默认情况下存在一种隐式转换,即定义了转换为此类类型的隐式转换机制。然而,这种机制并非总是合理的,甚至容易产生错误,因此,新标准增加了explicit关键字,用来限制隐式转换。
class Test {
public:
Test(); // 空构造函数
Test(double a); // 含一个参数的构造函数
Test(int a, int b); // 含两个参数的构造函数
Test(int a, double b = 1.2); // 带有默认初始值的构造函数
~Test();
};
// 调用
Test d1(12.3); // 直接调用含一个参数的构造函数
Test d2 = 1.2; // 也是调用含有一个参数的构造函数,但是包含一次隐式转换
Test d3(12, 13);
Test d3 = 12; // 隐式转换,调用带有默认初始值的构造函数Test(int a, double b = 1.2)
explicit可以阻止构造函数的隐式转换,但是只能对含有一个参数,或者有n个参数,但是其中 n-1 个参数是带有默认值的构造函数有效,其余的构造函数,explicit无法进行约束
class Test {
public:
Test() {} // 空构造函数
explicit Test(double a); // 该构造函数无法进行隐式类类型转换
explicit Test(int a, int b); // 含有两个参数,explicit对其无效,然而该构造函数本身也是不能隐式转换的
explicit Test(int a, double b = 1.2); // 该构造函数无法进行隐式类类型转换
~Test() {}
};
// 调用
Test d1(12.3); // 正确
Test d2 = 1.2; // 错误,不能进行隐式类类型转换
Test d3(12, 13); // 正确
Test d3 = 12; // 错误,不能进行隐式类类型转换
https://blog.csdn.net/readyone/article/details/112371671
implicit:
与其相对应的implicit则代表着隐式的类构造函数,因为在默认的情况下,类构造函数都是隐式的,所以后者没有前者常用,也较少被提及。
表示函数不会抛出异常的动态异常声明throw()也被新的noexcept异常声明所取代。
https://blog.csdn.net/LaoJiu_/article/details/50781352
代码解析:
namespace mystl
{
// helper struct
template <class T, T v>
struct m_integral_constant
{
static constexpr T value = v;
};
template <bool b>
using m_bool_constant = m_integral_constant<bool, b>;//c++ using 使用:取别名
//重命名
typedef m_bool_constant<true> m_true_type;//省略 一个模板参数 b
typedef m_bool_constant<false> m_false_type;
/*****************************************************************************************/
// type traits
// is_pair
// --- forward declaration begin
template <class T1, class T2>
struct pair;
// --- forward declaration end
template <class T>
struct is_pair : mystl::m_false_type {};//继承
template <class T1, class T2>
struct is_pair<mystl::pair<T1, T2>> : mystl::m_true_type {};
} // namespace mystl
四、construction
代码如下:
namespace mystl
{
// construct 构造对象
template <class Ty>
void construct(Ty* ptr)
{
::new ((void*)ptr) Ty();//全局参数
}
template <class Ty1, class Ty2>
void construct(Ty1* ptr, const Ty2& value)
{
::new ((void*)ptr) Ty1(value);//使用new 来 构造 一个copy construct :value
}
template <class Ty, class... Args>//init 列表 :(1,3,5,6)作为参数
void construct(Ty* ptr, Args&&... args)
{
::new ((void*)ptr) Ty(mystl::forward<Args>(args)...);//完美保持右值属性 参考:
}
// destroy 将对象析构
template <class Ty>
void destroy_one(Ty*, std::true_type) {}
template <class Ty>
void destroy_one(Ty* pointer, std::false_type)
{
if (pointer != nullptr)
{
pointer->~Ty();
}
}
template <class ForwardIter>
void destroy_cat(ForwardIter , ForwardIter , std::true_type) {}//cat 有浏览的意思 一个一个来解析(Iter:Iterator)
template <class ForwardIter>
void destroy_cat(ForwardIter first, ForwardIter last, std::false_type)
{
for (; first != last; ++first)
destroy(&*first);
}
template <class Ty>
void destroy(Ty* pointer)
{
// determine whether remove_all_extents_t<_Ty> is a reference type or can trivially be explicitly destroyed
destroy_one(pointer, std::is_trivially_destructible<Ty>{});//
}
template <class ForwardIter>
void destroy(ForwardIter first, ForwardIter last)
{
destroy_cat(first, last, std::is_trivially_destructible<
typename iterator_traits<ForwardIter>::value_type>{});
}
五、util
1 move和forward
function:
//function;std::move是为性能而生。
//std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。
//用法 :
//原lvalue值被moved from之后值被转移, 所以为空字符串.
typename std::remove_reference<T>::type&& move(T&& arg) noexcept
{
return std::remove_reference<T>::type&& > (arg);
}
example:
int main()
{
std::string a = "shdsda";
std::string b = std::move(a);
std::cout << a << std::endl;
std::cout << b << std::endl;
}//printf:a ‘空’
template <class T>
T&& forward(typename std::remove_reference<T>::type& arg) noexcept
{
return static_cast<T&&>(arg);//
}
//保证右值属性
//首先, forward常用于template函数中, 使用的时候必须要多带一个template参数T: forward, 代码略复杂;
//还有, 明确只需要move的情况而用forward, 代码意图不清晰, 其他人看着理解起来比较费劲.
//更技术上来说, 他们都可以被static_cast替代. 为什么不用static_cast呢? 也就是为了读着方便易懂.
2 pair
顾名思义:
条件判断
struct pair
{
typedef Ty1 first_type;
typedef Ty2 second_type;
first_type first; // 保存第一个数据
second_type second; // 保存第二个数据
template <class Other1 = Ty1, class Other2 = Ty2,
typename = typename std::enable_if<//如果ture 就void
std::is_default_constructible<Other1>::value &&
std::is_default_constructible<Other2>::value, void>::type>
constexpr pair(): first(), second(){}//typename = typename
//由于第二个模板参数的类型是依赖模板lfEnableIf的嵌套类型,
//因此您需要使用关键字typename来告诉编译器成员Type实际上是指类型而不是其他东西(即消除歧义)。//
//同样,模板的第二个参数是无名的,但如果您愿意,可以给它命名。它不会改变任何东西
};
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)