模板
- 模板是一组函数或类的参数实现。
- 编译器能够在需要使用函数或类模板时,用模板生成一个具体的函数或者类的定义。
- 也可以定义参数化类型的模板,因此模板并不是可执行代码,而是用于生成代码的蓝图或配方
- 因此一个从来没有被使用过的模板,它会被编译器忽略,不会生成可执行代码。
- 也就是说,如果一个模板程序包含了一些编程错误,但这个模板程序没有被使用,那它包含的这些错误在编译阶段是不会被发现的。只有用于生成代码时,才会被编译器标识出来。
unique_ptr
简述
-
unique_ptr<T>
对象指向了一个对象,它独享了这个对象的所有权。 -
不能指定或复制一个
unique_ptr<T>
对象。- 因此不能以传值的方式将一个
unique_ptr<T>
对象传入函数中,必须使用引用。 - 另外,
unique_ptr<T>
可以作为一个函数的返回值,原因是不会被拷贝,但是必须以隐式移动运算的方式返回。
不会拷贝的原因是,函数的返回值,作为一个将亡值,编译器对这种情况会使用移动的方式。
- 因此不能以传值的方式将一个
-
可以使用
std::move
转义所有权
1 2 3 |
std::unique_ptr<std::string> pname {new std::string{"aet"}}; std::cout << *pname << std::endl; |
make_unique
1 2 3 4 5 6 7 |
auto pname = std::make_unique<std::string>("aet"); auto pstr = std::make_unique<std::string>(6, '*'); // 数组 size_t len{10}; std::unique_ptr<int[]> pnumbers{new int[len]}; auto pnumberss = std::make_unique<int[]>(len); |
get
- 返回
unique_ptr<T>
所包含的原始指针
reset
- 调用无参的reset,会析构它指向的对象,原生指针将会被替换成空指针
- 传参给reset,智能指针之前所指向的对象会被析构。传入的参数的地址值将被替换为新对象的地址值
release
- 释放一个
unique_ptr<T>
所指向的对象,这个函数可以在不释放对象内存的情况下,将指向它的unique_ptr<T>
对象内容的原生指针设为空指针 - 返回所指对象的原生指针
swap
- 交换连个
unique_ptr<T>
指针的方式来交换两个对象
shared_ptr
简述
- 多个
shared_ptr<T>
对象可以指向同一个地址,所以shared_ptr<T>
允许共享一个对象的所有权。 - 引用计数保存了了指向给定地址的
shared_ptr<T>
对象的数量。- 每当有一个新的
shared_ptr<T>
对象指向一个特定堆地址时,引用计数就加1。 - 当一个
shared_ptr<T>
对象释放了或者指向了别的地址时,引用计数就减1。 - 当没有
shared_ptr<T>
指向这个地址时,引用计数将会变成0,在堆上为这个对象分配的内存就会释放。
- 每当有一个新的
1 2 3 4 |
std::shared_ptr<double> pdata {new double{999.99}}; *pdata = 888.88; std::cout << *pdata << std::endl; |
make_shared
1 |
auto pdata = std::make_shared<double>(999.99); |
get
- 从
shared_ptr<T>
得到一个原生指针
reset
- 无参reset,使所指向对象的引用计数减1
- 有参reset,效果一致
use_count
- 返回当前被调用对象的实例个数
weak_ptr
weak_ptr<T>
只能从一个shared_ptr<T>
对象创建,它们会指向相同的地址。- 创建一个
weak_ptr<T>
不会增加shared_ptr对象的引用计数,所以它会阻止指向的对象销毁。 - 当最后一个
shared_ptr<T>
引用被释放或重新指向一个不同的地址时,它们所指向对象的内存将被释放,即使相关的weak_ptr<T>
可能仍然存在。
1 2 3 4 |
auto pData = std::make_shared<X>(); std::weak_ptr<X> pwData { pData }; std::weak_ptr<X> pwData2 { pwData }; |
expired
- 先判断所指向的对象是否依然存在
- 不存在,返回true
1 2 3 |
if (pwData.expired()) { std::cout << "Object no longer exists." << std::endl; } |
lock
- 如果
weak_ptr<T>
指向的对象依然存在,lock会返回一个新的shared_ptr<T>
对象,锁住对象。 - 如果不存在,会返回一个具有空指针的
shared_ptr<T>
1 2 3 4 5 6 7 |
std::shared_ptr<X> pNew {pwData.lock()}; if (pNew) { std::cout << "a" << std::endl; } else { std::cout << "Object no longer exists" << std::endl; } |
使用weak_ptr的原因
- 避免在不经意间创建了一个循环引用
- 就是一个
shared_ptr<T>
对象pA,指向了另一个shared_ptr<T>
对象pB,导致两个对象都不能被释放。 - 通过使用
weak_ptr<T>
指向一个shared_ptr<T>
所指向的对象,就可以避免循环引用。原因是weak_ptr不会增加引用计数。
- 就是一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 循环引用 class CSB; class CSA { public: std::shared_ptr<CSB> ptr_; ~CSA() { std::cout << "csa is deleted" << std::endl; } }; class CSB { public: std::shared_ptr<CSA> ptr_; ~CSB() { std::cout << "csb is deleted" << std::endl; } }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
int main() { void* addr; { std::shared_ptr<CSA> pCSA{ new CSA }; std::shared_ptr<CSB> pCSB{ new CSB }; std::cout << "first--->" << std::endl; std::cout << pCSA.use_count() << std::endl; std::cout << pCSB.use_count() << std::endl; pCSA->ptr_ = pCSB; // pCSB引用计数为2 std::cout << "second--->" << std::endl; std::cout << pCSA.use_count() << std::endl; std::cout << pCSB.use_count() << std::endl; pCSB->ptr_ = pCSA; // pCSA引用计数为2 std::cout << "third--->" << std::endl; std::cout << pCSA.use_count() << std::endl; std::cout << pCSB.use_count() << std::endl; std::cout << "delete pCSA" << std::endl; addr = pCSA.get(); } // 在析构后,还是可以通过指针看到pCSAS的引用计数为1 // 没有释放掉,造成了内存泄漏 std::cout << ((CSA*)addr)->ptr_ << std::endl; return 0; } |
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ C++14_第一篇12/14
- ♥ C++_多线程相关03/12
- ♥ Soui九07/25
- ♥ 打包_7z生成自解压打包exe07/11
- ♥ 线程和协程10/31
- ♥ STL_stack05/19