1.第四章 智能指针
如何选择unique_ptr 和shared_ptr?
unique_ptr 的使用场景,最常见的就是拥有一个对象的所有权,就像传统 C 指针的最基础用法,保存一个申请于堆上的对象
auto q = std::make_unique<Foo>(1);//better
shared_ptr用法:
-
作为需要保存在容器里的对象,同时避免频繁创建引起性能上的开销
-
如果一个类的创建需要比较多的资源(例如比较大的的内存和拷贝),如果我们直接保存在容器里可能会在拷贝时产生比较大的性能损失,这个时候可以考虑使用
shared_ptr
,然后将shared_ptr
保存于容器。
vector<std::shared_ptr<Foo>> foos;
// ...
for(auto &foo : foos){
process_func(*foo);
}
1.如何理解 保证析构在所有代码路径上都仅执行一次:
同一对象的析构(函数)只执行一次。
2.工厂函数,工厂模式
使用父类指针创建,替换,转化子类对象的方法叫工厂模式
3.理解RTTI
参考:C++运行阶段类型识别(Runtime Type Identification)(C++新特性)_SOC罗三炮的博客-CSDN博客
C++的 RTTI 观念和用途(非常详细) - findumars - 博客园 (cnblogs.com)
4.条款18 std::unique_ptr
Effective Modern C++ 有如下代码:
template<typename... Ts>
std::unique_ptr<Investment, decltype(delInvmt)>
makeInvestment(Ts&&... params)
{
std::unique_ptr<Investment, decltype(delInvmt)>
pInv(nullptr, delInvmt);
..........
}
std::unique_ptr<Investment, decltype(delInvmt)> 第二个参数是自定义析构器。
参考源码:
// _Tp为管理对象的类型,_Dp为析构器的类型
// default_delete是默认析构器,默认析构器中使用delete运算符实现对象的析构
template <typename _Tp, typename _Dp = default_delete<_Tp>>
class unique_ptr
{
// 使用__uniq_ptr_impl管理要管理的heap对象
// _Tp为管理对象类型,_Dp为析构器
__uniq_ptr_impl<_Tp, _Dp> _M_t;
public:
using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
using element_type = _Tp;
using deleter_type = _Dp;
};
5.循环引用
class B;
class A
{
public:
shared_ptr<B> m_b;
};
class B
{
public:
shared_ptr<A> m_a;
};
int main()
{
while (true)
{
shared_ptr<A> a(new A); //new出来的A的引用计数此时为1
shared_ptr<B> b(new B); //new出来的B的引用计数此时为1
a->m_b = b; //B的引用计数增加为2
b->m_a = a; //A的引用计数增加为2
}
//b先出作用域,B的引用计数减少为1,不为0,所以堆上的B空间没有被释放
//且B持有的A也没有机会被析构,A的引用计数也完全没减少
//a后出作用域,同理A的引用计数减少为1,不为0,所以堆上A的空间也没有被释放
}
6.条款21
1.异常安全:使用new创建shared_ptr会分成两步:1.创建裸指针。2.利用构造函数创建shared_ptr
2.性能提升:使用new会进行两次内存分配,1.原始对象。2.shared_ptr控制块
make系列的限制:1.不能使用自定义析构器。2.不能使用大括号初始化(使用auto)
7.条款22
如何理解Pimpl惯用法减少了构建遍数。
减少编译依赖:原始类的头文件只包含了Impl类的前向声明,而不包含具体的实现细节。因此,当Impl类的实现发生变化时,只有与Impl类相关的源文件需要重新编译,而不需要重新编译使用原始类的其他源文件。这降低了构建遍数,提高了编译速度。
第五章
完美转发:一个函数把自己的形参传递(转发)给另一个函数。目的是为了让第二个函数接受第一个函数所接受的同一对象。完美转发的含义是我们不仅转发对象,还转发其显著特征:类别、左值还是右值,以及const volation等饰词。
运行万能引用,因为只有万能引用形参才会将传入的实参是左值还是右值这一信息加以编码。
完美转发失败
1. 使用大括号初始化列表时
(1)失败原因分析:由于转发函数是个模板函数,而在模板类型推导中,大括号初始不能自动被推导为std::initializer_list<T>。
(2)解决方案:先用auto声明一个局部变量,再将该局部变量传递给转发函数。
第七章 并发API
看不太明白
暂时先记录