//
// SmartPointer.cpp
// test_cpp_protocol_01
//
// Created by jeffasd on 2016/10/24.
// Copyright © 2016年 jeffasd. All rights reserved.
//
#include "SmartPointer.h"
#include <stdio.h>
#include <memory.h>
#include <string>
#include "Person.h"
SmartPointer::SmartPointer()
:_data(3)
{
printf("SmartPointer constructor\n");
_data = int(3);
}
SmartPointer::~SmartPointer() {
printf("SmartPointer destructor\n");
}
void SmartPointer::showName() {
printf("smartPointer showName\n");
// 智能指针的各种初始化方法
std::shared_ptr<int> sharedPtr = std::make_shared<int>(3);
std::shared_ptr<Student> sharedPtrOne(new Student());
std::shared_ptr<Student> sharedPtrTwo = std::make_shared<Student>();
sharedPtrTwo->writeWorldWithString("hello wolrd");
std::shared_ptr<Student> _imp = std::shared_ptr<Student>(new Student());
std::shared_ptr<Student> sharedPtrThree(sharedPtrOne); // copy 引用计数+1
/**
每个shared_ptr都有一个关联的计数值,通常称为引用计数。无论何时我们拷贝一个shared_ptr,计数器都会递增。
例如,当用一个shared_ptr初始化另一个shred_ptr,或将它当做参数传递给一个函数以及作为函数的返回值时,它
所关联的计数器就会递增。当我们给shared_ptr赋予一个新值或是shared_ptr被销毁(例如一个局部的
shared_ptr离开其作用域)时,计数器就会递减。一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理
的对象。
*/
Student *xiaoming = new (std::nothrow) Student ();
Student *xiaohua = new (std::nothrow) Student ();
// 注意不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存
std::shared_ptr<Student> sharedPtrFive(xiaoming); // 当一个对象指针使用智能指针时 以后不要再使用此对象指针 而要使用智能指针
// warring 对一个原始指针初始化多个shared_ptr,会造成二次释放同一个内存,此用法不正确
// std::shared_ptr<Student> sharedPtrErrorUse(xiaoming);
xiaoming->writeWorldWithString("hello xiaoming"); // 使用智能指针之后最好不要再使用原始指针 不推荐这样用
//返回与sharedPtrFive共享xiaoming对象的智能指针数量,这个操作可能会比较慢,一般调试的时候用,正式情况下一般不用
//一个bool函数 如果只有一个引用计数则返回true,如果不是则返回false
bool isUnique = sharedPtrFive.unique();
printf("sharedPtrFive is Unique %s", isUnique ? "true" : "false");
// use_count()获取有多少个智能指针共享同一个内部数据指针
printf("reference is %ld\n", sharedPtrFive.use_count());
// shared_ptr多个指针指向相同的对象。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。
// 初始化。智能指针是个模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。不能将指针直接赋值给一个智能指针,一个是类,一个是指针。例如std::shared_ptr<int> p4 = new int(1);的写法是错误的
// 拷贝和赋值根据是否有新的智能指针指向了同一个对象,如果有新增智能指针指向了同一个对象,引用计数加1 否则引用计数不加1
// 注意不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存
// 注意避免循环引用,shared_ptr的一个最大的陷阱是循环引用,循环,循环引用会导致堆内存无法正确释放,导致内存泄漏。
// 拷贝和赋值根据是否有新的智能指针指向了同一个对象,如果有新增智能指针指向了同一个对象,引用计数加1 否则引用计数不加1
// 有新的sharedPtrSix指向了xiaoming对象 引用计数加1
std::shared_ptr<Student> sharedPtrSix = sharedPtrFive; // copy 赋值 引用计数+1
// std::shared_ptr<Student> sharedPtrSix(sharedPtrFive); // copy 赋值 引用计数+1
// use_count 引用计数详解:指的是有多少个shared_ptr指向同一个对象 此处use_count为2 sharedPtrSix和sharedPtrFive 均指向xiaoming对象
// 没有新的智能指针指向了xiaoming对象 引用计数不加1
sharedPtrFive = sharedPtrSix;
printf("reference is %ld\n", sharedPtrFive.use_count());
printf("reference is %ld\n", sharedPtrSix.use_count());
sharedPtrFive->writeWorldWithString("sharedPtrFive");
sharedPtrSix->writeWorldWithString("sharedPtrSix");
// 重新赋值
// sharedPtrFive.reset(xiaohua);
sharedPtrFive.reset(); // 将sharedPtrFive的引用计数减一 引用计数最小值为0
sharedPtrFive.reset(); // 将sharedPtrFive的引用计数减一 引用计数最小值为0
sharedPtrFive.reset(); // 将sharedPtrFive的引用计数减一 引用计数最小值为0
printf("reference is %ld\n", sharedPtrFive.use_count());
printf("reference is %ld\n", sharedPtrSix.use_count());
sharedPtrSix.reset(); // 将sharedPtrSix的引用计数减一 引用计数最小值为0
// unique_ptr是一个独占的智能指针,即unique_ptr不支持复制,但是支持通过move转移内部指针
// Student *xiaogang = new (std::nothrow) Student ();
// std::unique_ptr<Student> uniquePtr(xiaogang);
std::unique_ptr<Student> uniquePtr = std::make_unique<Student>();
std::unique_ptr<Student> uniquePtrOne = std::make_unique<Student>();
// release()释放原来智能指针指向的指针,只负责转移控制权,不负责释放内存,常见的用法
// 所以如果单独用: 则会导致uniquePtr丢了控制权的同时,原来的内存得不到释放
// uniquePtr.release()
// 注意release()只转移控制权,并不释放内存,而reset和=nullptr操作会释放原来的内存
// uniquePtr.reset();// 释放p原来的对象,并将其置为nullptr,
uniquePtr = nullptr; // 等同于uniquePtr.reset();
uniquePtr = std::move(uniquePtrOne); // 转移控制权
printf("reference \n");
// weak_ptr可以看做shared_ptr的助手,weak_ptr要和shared_ptr配套一起使用。当创建一个weak_ptr时,要用一个shared_ptr来初始化它。
// 复制shared_ptr是会增加内部数据的引用计数,但是复制weak_ptr时,以及由shared_ptr构造weak_ptr时,是不会增加引用计数的;且weak_ptr没有重载*、->操作符,所以不能通过*、->操作符操作智能指针的内部数据
/**
因为weak_pt不增加引用计数,我们可以任意构造weak_ptr,任意释放weak_ptr,却不会影响智能指针中内部数据的释放(内部数据何时释放,只取决于shared_ptr)。那么weak_ptr有什么用呢?weak_ptr可以用来监看shared_ptr:
weak_ptr::use_count()查看有多少个shared_ptr共享同一个内部数据
weak_ptr::expired判断shared_ptr是否有效,即shared_ptr内部数据是否被释放
weak_ptr是否可以监看shared_ptr中的内部数据呢?因为weak_ptr是弱指针,所以不能直接访问,但是可以通过weak_ptr::lock间接访问。
*/
std::shared_ptr<Student> sharedPtrSeven = std::make_shared<Student>();
std::weak_ptr<Student> weakPtr = sharedPtrSeven;
printf("weak_ptr reference is %ld\n", weakPtr.use_count());
// 相当于把weak_ptr转换为shared_ptr,然后通过shared_ptr去访问。
std::shared_ptr<Student> sharedPtrLock = weakPtr.lock(); // 将lock返回的智能指针赋值给sharedPtrLock 引用计数会加1
printf("weak_ptr reference is %ld\n", weakPtr.use_count());
printf("sharedPtr reference is %ld\n", sharedPtrSeven.use_count());
weakPtr.lock(); // 没有将lock函数返回的智能指针赋值给任何其他智能指针 引用计数不会加1
printf("weak_ptr reference is %ld\n", weakPtr.use_count());
printf("sharedPtr reference is %ld\n", sharedPtrSeven.use_count());
printf("reference");
}