C++类(六)——C++11的初始化列表、左值引用和右值引用、智能指针

C++11的初始化列表

基本概念:https://www.cnblogs.com/LuckCoder/p/8467656.html

class A {
public:
	explicit A(int value) : m_value(value) {}
private:
	int m_value;
};

static void newVersionConstruct() {
	int avector[] = { 1, 2, 3 };
	std::vector<int> bv = { 1, 2, 3 };
	A a(10);
	A b{ 3 };

	//bool类型转成int类型的精度没有损失。true会转化成0,false转成1.
	//因为没有精度损失,所以这种转化是允许的
	A c(true);  
	A d{ true };

	//A e(1.1);
	//A f{1.0};
}

 

 

 

左值引用和右值引用

//由于传入的参数类型是const引用,因此传入左值或者右值都是可以的
void printInfo(const int& a) {
	std::cout << a << std::endl;
}

static void leftRefAndRightRef() {

	int a = 10;
	int& refA = a;             //引用类似于别名
	const int& constRefA = a;  //const引用可以防止对原数据的修改

	std::cout << " a " << a << " ref of a " << refA << " const ref a "
		<< constRefA << std::endl;

	// this is a error
	//int& refB = 10;
	const int& constRefB = 10;  //const引用可以指向一个右值
	printInfo(constRefB);
	printInfo(10);
	printInfo(a);
	printInfo(refA);
	std::cout << "different version const ref " << constRefB << std::endl;

	auto&& rrA = 10;  //右值引用
	const int&& crrB = 20;
	rrA = 30;  //可以通过右值引用改变一个右值的大小
	std::cout << " right ref of b " << rrA << " const right ref b "
		<< crrB << std::endl;

	int b = 20;
	// 下面两句是错误的,编译器不支持隐式的将左值转成右值
	//int&& rrB = b;
	//const int&& crrB = b;

	//显示的将左值转成右值
	int&& newRRB = std::move(b);
	const int&& cNewRRB = std::move(b);

	//b的地址和newRRB的地址和cNewRRB的地址相同
	std::cout << " b " << b << " right ref of b " << newRRB << " const right ref b "
		<< cNewRRB << std::endl;
	std::cout << "address " << &b << " ref " << &newRRB << " c ref " << &cNewRRB << std::endl;
}

 

 


构造函数和析构函数的经典应用——智能指针

 

引言

//getName和getName2两个函数都只返回一个指针,这种设计存在一定的的缺陷:
//用户不明确指针指向的内存是否属于自己管理的范围
//多线程的环境下,该函数返回的指针只能当场使用,因为其他线程可以修改valueGroup的值
const char* getName() {
	static char valueGroup[1000];
	// do some thing
	return valueGroup;
}
//多线程下返回的指针所指的值可以一直用,但是要记得手动释放内存
const char* getName2() {
	char* value = (char*)malloc(1000);
	// do something
	return value;
}
//下面的函数可以解决上面函数的问题:返回的指针所指的那块内存是否需要程序员去手动释放
char* getName(char* v, size_t bufferSize) {
	// do something
	return v;
}

对于堆上的内存,可以使用malloc和free或者new和delete进行控制。但是如果不注意,还是会发生内存泄漏。如下:

void badThing() {
	//抛出异常
	throw 1;
}

void versionOne() {
	//void*
	int* ageC = (int*)malloc(sizeof(int));
	//判断是否生成成功
	if (ageC) {}
	free(agcC);
	char* c = (char*)malloc(100);
	free(c);

	int* age = new int(25);
	int* height = new int(160);

	//当badThing抛出异常之后,即使下面写了delete,age和height所指向的内存依然泄漏了
	badThing();

	std::cout << "VersionOne: your age is " << *age << ", and your height is "
		<< *height << std::endl;

	// if forget, TOO BAD thing will happen
	delete height;
	delete age;
}

当函数badThing()抛出异常之后,即使下面写了delete,age和height所指向的内存依然泄漏了。

如果我们写了一个类,用来控制内存的产生和释放,如下,在多线程的情况下,还是会出现一些问题:

class SafeIntPointer {
public:
	explicit SafeIntPointer(int v) : m_value(new int(v)), m_used(1) {}
	~SafeIntPointer() {
		//下面的三句代码存在问题:在多线程情况下,可能会出现
		//多个线程同时满足条件if (m_used <= 0)的情况
		//此时就会出现问题m_value所指向的资源会被重复释放
		m_used--;
		if (m_used <= 0)
			delete m_value;
	}
	// copy
	// operator =
	int* get() { return m_value; }
private:
	int m_used;  //记录使用者人数,当该值为0时,释放资源
	int* m_value;
};

为此,C++11推出用于管理内存的智能指针——shared_ptr

void versionTwo() {
	std::shared_ptr<int> age(new int(28));
	std::shared_ptr<int> height(new int(160));

	std::cout << "VersionTwo: your age is " << *age << ", and your height is "
		<< *height << std::endl;
	// 不需要做任何额外的事情,内存会自动的释放掉
}

 

智能指针总体概述

  • auto_ptr  不推荐使用
  • shared_ptr 通过引用来实现指针共享
  •  weak_ptr     和shared_ptr搭配使用
  • unique_ptr   一个指针只能有一个用户使用
  • enable_shared_from_this  // CRTP

 

 

 

shared_ptr

基础

  • 多个shared_ptr可以共享同一个对象,对象的最末一个拥有者有责任销毁对象,并清理与该对象相关的所有资源。
  • 一般而言,shared pointer并非线程安全
#include<iostream>
#include<string>
#include<vector>
#include<memory> //for shared_ptrshared_ptr
using namespace std;

int main(){

    shared_ptr<string> pNico(new string("nico"),
    [](string *p){
        cout<<"delete"<<*p<<endl;
        delete p;
    });

    shared_ptr<string> pJutta(new string("jutta"));
    //shared_ptr<string> pJutta = new string("jutta");             // error,shared_ptr's constructor is explicit
    //shared_ptr<string> pJutta{new string("jutta")};              // ok
    //shared_ptr<string> pJutta = make_shared<string>("nico");     // ok

    (*pNico)[0] = 'N';
    pJutta->replace(0, 1, "J");

    vector<shared_ptr<string>> whoMadeCoffee;
    whoMadeCoffee.push_back(pJutta);

    cout<<"use_count:"<<whoMadeCoffee[0].use_count()<<endl;

    whoMadeCoffee.push_back(pJutta);
    whoMadeCoffee.push_back(pNico);
    whoMadeCoffee.push_back(pJutta);
    whoMadeCoffee.push_back(pNico);

    for(auto ptr : whoMadeCoffee){
        cout<<*ptr<<" ";
    }
    cout<<endl;

    *pNico = "Nicoai";

     for(auto ptr : whoMadeCoffee){
        cout<<*ptr<<" ";
    }
    cout<<endl;   

    cout<<"use_count:"<<whoMadeCoffee[0].use_count()<<endl;

    pNico =nullptr;
    cout<<"use_count:"<<whoMadeCoffee[2].use_count()<<endl;
    whoMadeCoffee.resize(2);
    cout<<"use_count:"<<whoMadeCoffee[2].use_count()<<endl;

    return 0;
}

运行结果:

 

 

shared_ptr的使用例子

/*
确保“指向某临时文件”最后一个reference被销毁时,该文件被移除
*/

#include<fstream>
#include<string>
#include<vector>
#include<memory>  //for shared_ptr
#include<cstdio>  //for remove()
using namespace std;

class FileDelter{
private:
    string filename;

public:
    FileDelter(const string& fn):
        filename(fn){}
    void operator()(std::ofstream* fp){
        fp->close();
        std::remove(filename.c_str());
    }
};

int main(){
    //create and open temporary file
    std::shared_ptr<ofstream>fp(new std::ofstream("tmpfile.txt"),
                                FileDelter("tmpfile.txt"));
}

 

// 使用shared_ptr打开共享内存

#include<memory>
#include<sys/mman.h>  //for shared memory
#include<fcntl.h>
#include<unistd.h>
#include<cstring>     //for strerror()
#include<cerrno>      //for errno
#include<string>
#include<iostream>

class shared_ptr_shared_memory {
public:
    void operator()(int* p){
        std::cout<<"unlink/tmp1234"<<std::endl;
        if(shm_unlink("/tmp1234")!=0){
            std::cerr<<"OOPS: shm_unlink() failed" <<std::endl;
        }
    }
};

std::shared_ptr<int> get_shared_memory(int num){
    void* mem;
    int shmfd = shm_open("/tmp1234", O_CREAT|O_RDWR, S_IRWXU|S_IRWXG);
    if(shmfd<0){
        throw std::string(strerror(errno));
    }

    if(ftruncate(shmfd, num*sizeof(int))==-1){
        throw std::string(strerror(errno));
    }

    mem = mmap(nullptr, num*sizeof(int), PROT_READ | PROT_WRITE,
    MAP_SHARED, shmfd, 0);

    if(mem ==MAP_FAILED){
        throw std::string(strerror(errno));
    }

    return std::shared_ptr<int>(static_cast<int*>(mem), shared_ptr_shared_memory());

}

int main(){
    std::shared_ptr<int>smp(get_shared_memory(100));

    for(int i=0;i<100;++i){
        //shared_ptr 没有提供指针运算和operator[],因此如果想访问内存,
        //需要使用get()获得被shared_ptr包裹(wrapped)的内部指针
        smp.get()[i] = i*42; //same as (&*smp)[i] = i*42;
    }

    //dealwith shared memory somewhere else
    std::cout<<"<return>"<<std::endl;
    std::cin.get();

    //release shared memnry here
    smp.reset();

}

 

class Object {
public:
	Object(int id) : m_id(id) { std::cout << "init obj " << m_id << std::endl; }
	~Object() { std::cout << "bye bye " << m_id << std::endl; }
	int id() const { return m_id; }
private:
	int m_id;
};

typedef std::shared_ptr<Object> ObjectPtr;

//多线程情况下,推荐以值的形式传入智能指针
void print(ObjectPtr obj) {
	//打印出来是3,因为作为值传入,会对智能指针进行一次拷贝
  std::cout << "count " << obj.use_count() << " id " << obj->id() << std::endl; // 3
}

void printRef(const ObjectPtr& obj) {
	//打印出来是2,因为作为引用传入
  std::cout << "ref count " << obj.use_count() << " id " << obj->id()
            << std::endl; // 2
}

//以该类本身作为参数传入也是可以的。否则作为只能通过只能指针作为参数
void print(const Object& obj) {}

void interfaceOfSharedPtr() {
	ObjectPtr null;
	std::cout << "ref count is " << null.use_count() << std::endl; // 0
	ObjectPtr obj(new Object(1));
	std::cout << "ref count is " << obj.use_count() << std::endl; // 1
	ObjectPtr obj2(obj);  //通过拷贝,共享智能指针。obj和obj2指向同一份资源
	std::cout << "ref count is " << obj.use_count() << std::endl; // 2
	std::cout << "ref count obj2 is " << obj2.use_count() << std::endl; // 2
	ObjectPtr obj3 = obj;  //通过拷贝,共享智能指针。
	std::cout << "ref count is " << obj.use_count() << std::endl; // 3
	obj2.reset(); // reset means what?   reset指的是obj2不再被使用
	obj2 = nullptr;  //这句和上面这句的功能是相同的
	std::cout << "ref count is " << obj.use_count() << std::endl; // 2

	ObjectPtr obj4;
	obj3.swap(obj4);  //交换obj4和obj3所指向的资源
	std::swap(obj3, obj4);  //这句和上一句的功能相同。
	std::cout << "ref count is " << obj.use_count() << std::endl; // 2

	//通过get获取obj指向的资源。p是一个裸指针,可以操作obj所指向的资源
	//get函数不到万不得已不要使用,因为如果p调用了delete,会发生什么事情呢
	//get是为了第三方函数的接口所准备的,不到万不得已不要使用
	auto p = obj.get();  
	if(p) std::cout << "id is " << p->id() << std::endl;

	if(obj) { // operator bool  判断只能指针是否为空。智能指针重载了“->”和“operator*”
		std::cout << "p id is " << obj->id() << std::endl; // operator ->
		std::cout << "ref id is " << (*obj).id() << std::endl; // operator *
	}

	obj4 = nullptr;
	//if(obj.unique())              判断是否只有一个人在使用他
	//if(obj.use_count() == 1)      use_count可能会有意想不到的效率损失
	//因为智能指针可能在多线程下使用,use_count要处理多线程的情况。
	std::cout << "only one hold ptr " << obj.unique() << std::endl;
	print(obj);   //可以把智能指针作为值进行传入。传入后会对智能指针进行一次拷贝
	std::cout << "ref count is " << obj.use_count() << std::endl; // 2
	printRef(obj); //可以把只能指针作为引用传入

	print(*obj); //以该类本身作为参数传入也是可以的
}

void deleterOfObject(Object* obj) {
	if (obj)
		std::cout << "delete obj " << obj->id() << std::endl;
	delete obj;
}

void useDeleter() {
	//传入的参数是裸指针以及处理指针的函数
	ObjectPtr obj(new Object(2), deleterOfObject);
	ObjectPtr obj2 = obj;
}

 

 

有些情况下shared_ptr无法处理

当存在彼此依赖关系的时候,两个类都在等待对方释放资源之后再释放资源。因此造成了内存泄漏。例子如下:

#include<iostream>
#include<string>
#include<vector>
#include<memory>
using namespace std;

class Person{
    public:
    string name;
    shared_ptr<Person>mother;
    shared_ptr<Person>father;
    vector<shared_ptr<Person>>kids;

    Person(const string& n,
        shared_ptr<Person>m=nullptr,
        shared_ptr<Person> f = nullptr)
        :name(n), mother(m), father(f){}

    ~Person(){
        cout<<"delete"<<name<<endl;
    }
};

shared_ptr<Person> initFamily(const string&name){
    shared_ptr<Person> mom(new Person(name+"'s mom"));
    shared_ptr<Person>dad(new Person(name +"'s dad"));
    shared_ptr<Person> kid(new Person(name, mom, dad));
    mom->kids.push_back(kid);
    dad->kids.push_back(kid);
    return kid;
}

int main(){
    shared_ptr<Person> p = initFamily("nico");

    cout<<"nico's family exists"<<endl;
    cout<<"-nico is shared "<<p.use_count()<<" times"<<endl;
    cout<<"-name of 1st kid of nico's mom: "
        <<p->mother->kids[0]->name <<endl;

    p=initFamily("jim");
    cout<<"jim's family exists"<<endl;
}

运行结果:

 

代码中 p指向家挺中的最密一个handle,而在内部,每个person对象都有着reference从kid指向父母以及反向指向。因此,在p被赋值之前,nico被共享三次。

当我们释放受伤最末一个指向该家挺的handle——也许是对p指派一个新person或者一个nullptr,也许是main()结束时离开了p作用域——没有任何person会被释放,因为他们都至少被一个shared pointer指向。于是每个person的析构函数从未被调用。

如果存在彼此之间的循环引用关系,则shared_ptr不能释放掉彼此应该释放的资源。为了打破局限性,引入weak_ptr。

 

 


weak_ptr

  • weak_ptr可以打破循环引用。weak_ptr可能管理了一份资源,当weak_ptr管理的资源被外部其他智能指针管理,则该资源是有效的,否则,weak_ptr管理的资源是无效的。
  • weak_ptr可以安全的实现“共享但不拥有”的需求。一旦最后一个拥有该对象的shared_ptr失去了拥有权,任何weak_ptr都会自动成空。这样可以有效的避免”访问已被释放的数据“

 

 

weak_ptr的基本用法

void sharedPtrWithWeakPtr() {
	//typedef std::shared_ptr<Object> ObjectPtr;
	ObjectPtr obj(new Object(1));

	typedef std::weak_ptr<Object> WeakObjectPtr;
	WeakObjectPtr weakObj2;
	WeakObjectPtr weakObj(obj);
	WeakObjectPtr weakObj3(obj);

	//由于只有一个shared_ptr在管理这份资源。哪怕存在两个weak_ptr在监听这份资源
	std::cout << "obj use count is " << obj.use_count() << std::endl; // 1
	{
		//希望使用weak_ptr时,需要对weak_ptr进行转换。
		//调用lock函数,当外部引用不小于1时,则返回一个有效指针
		auto p = weakObj.lock(); // auto === ObjectPtr
		if(p) {
			//p.unique()的结果是false。因为p.use_count() >= 2
			//因为当weak_ptr管理的那份资源在外部还被其他智能指针所管理的时候,
			//weak_ptr所管理的资源才是有效的。因此 p.use_count() >= 2
			std::cout << p.unique() << std::endl;
			// do what you want to do
		} else {
			//说明这份资源已经没有外部智能指针进行管理了
			//此时返回的p是一个空指针
			//说明weak_ptr所管理的资源已经被析构了
		}
	}

	//调用reset函数放弃对Object1的管理。现在管理Object2
	obj.reset(new Object(2));
	{
		//weakObj管理的是Object1,然而已经没有shared_ptr管理Object1了,
		//此时调用lock函数会返回一个空指针
		auto p = weakObj.lock();
		if(p) {
			assert(false);
			// do what you want to do
		} else {

		}
	}

	//此时weak_tr又指向了和obj相同的资源
	weakObj = obj;
	//expired函数判断资源是否过期。
	if(weakObj.expired()) {
		//说明weak_ptr指向的资源已经过期
	} else {

	}
}

 

 

 

现在来看一下如何使用weak_ptr去解决shared_ptr无法解决的循环调用问题

#include<iostream>
#include<string>
#include<vector>
#include<memory>
using namespace std;

class Person{
    public:
    string name;
    shared_ptr<Person>mother;
    shared_ptr<Person>father;
    vector<weak_ptr<Person>>kids; //weak_ptr

    Person(const string& n,
        shared_ptr<Person>m=nullptr,
        shared_ptr<Person> f = nullptr)
        :name(n), mother(m), father(f){}

    ~Person(){
        cout<<"delete"<<name<<endl;
    }
};

shared_ptr<Person> initFamily(const string&name){
    shared_ptr<Person> mom(new Person(name+"'s mom"));
    shared_ptr<Person>dad(new Person(name +"'s dad"));
    shared_ptr<Person> kid(new Person(name, mom, dad));
    mom->kids.push_back(kid);
    dad->kids.push_back(kid);
    return kid;
}

int main(){
    shared_ptr<Person> p = initFamily("nico");

    cout<<"nico's family exists"<<endl;
    cout<<"-nico is shared "<<p.use_count()<<" times"<<endl;
    cout<<"-name of 1st kid of nico's mom: "
        <<p->mother->kids[0].lock()->name <<endl; //differ with shared_ptr: p->mother->kids[0]->name

    p=initFamily("jim");
    cout<<"jim's family exists"<<endl;
} 

 

运行结果

 

如果不确定隐身于weak pointer背后的对象是否仍旧存货,你有一下几个选择:

1. 调用expired(),它会在weak_ptr不在共享对象时返回true。折等同于检查use_count()是否位0,但是速度较快。

2. 可以使用相应的shared_ptr构造函数明确将weak_ptr转换位shared_ptr。如果被指对象以及该不存在了,该构造函数明确将会抛出一个bad_weak_ptr异常。

3. 调用use_count(),询问相应对象的拥有者数量。如果返回0表示不存在任何有效对象。use_count()并不是很有效率,因此通常并不是很有效率。

 

 

 

enable_shared_from_this 和weakptr辅助sharedptr

#include <cassert>
#include <memory>
#include <iostream>
// auto_ptr
// shared_ptr
// enable_shared_from_this // CRTP
// weak_ptr
// unique_ptr
void sharedPtrNotice();
class Parent;
typedef std::shared_ptr<Parent> ParentPtr;
typedef std::weak_ptr<Parent> WeakParentPtr;

// public std::enable_shared_from_this<Child>歧义模板递归参数模式   CRTP
class Child : public std::enable_shared_from_this<Child> {
	public:
		WeakParentPtr father;
		~Child();
		Child();
		void checkRelation();
};
typedef std::shared_ptr<Child> ChildPtr;
typedef std::weak_ptr<Child> WeakChildPtr;

class Parent : public std::enable_shared_from_this<Parent> {
	public:
		WeakChildPtr son;
		~Parent();
		Parent();
		void checkRelation();
};

void handleChildAndParentRef(const Parent& p, const Child& c) {
	auto cp = c.father.lock();
	auto pc = p.son.lock();
	if(cp.get() == &p && pc.get() == &c) {
		std::cout << "right relation\n";
	} else {
		std::cout << "oop!!!!!\n";
	}
}

//传入const智能指针的引用是为了减少拷贝次数
void handleChildAndParent(const ParentPtr& p, const ChildPtr& c) {
	//assert(c);  可以用于验证传入的是否有效
	//如果传入的是空指针,则会抛出异常

	//weakptr通过lock函数获得shared_ptr.
	auto cp = c->father.lock();
	auto pc = p->son.lock();
	if(cp == p && pc == c) {
		std::cout << "right relation\n";
	} else {
		std::cout << "oop!!!!!\n";
	}
}

Child::Child() { std::cout << "hello child\n";}
Parent::Parent() { std::cout << "hello parent\n";}
Child::~Child() { std::cout << "bye child\n";}
Parent::~Parent() { std::cout << "bye parent\n";}

//调用handleChildAndParent
void Parent::checkRelation() {
	//weakptr不能直接用,要通过lock函数验证一下
	//如果son不是weakptr,则下面的过程可以改写成
	//handleChildAndParent(Parent的智能指针,son);
	auto ps = son.lock();
	if(ps) {
		// this
		handleChildAndParent(shared_from_this(), ps);
		//下面的写法是错误的,执行完之后,会调用一次析构函数。
		//从而导致析构函数被调用两次
		/*
		ParentPtr p(this);
		handleChildAndParent(p, ps);
		*/
	}
	std::cout << "after call checkRelation\n";
}

void Child::checkRelation() {
	// we call handleChildAndParent
}

 

 

 


 unique_ptr——在某个特定的时刻,只会有一个unique_ptr来管理这一个指针

 

unique_ptr是一种在异常发生时可帮助避免资源泄露的smart pointer。这个smart pointer实现了独占式拥有的概念。

 

 unique_ptr的接口使用例子

class Object {
 public:
  Object(int id) : m_id(id) { std::cout << "init obj " << m_id << std::endl; }
  ~Object() { std::cout << "bye bye " << m_id << std::endl; }
	int id() const { return m_id;}
private:
	int m_id;
};

typedef std::unique_ptr<Object> UniqueObjectPtr;

void print(const UniqueObjectPtr& obj) {}
void transfer(UniqueObjectPtr obj) {
	std::cout << obj->id() << std::endl;
}

void uniquePtr() {
	UniqueObjectPtr obj(new Object(1));
	auto p = obj.get(); // 获得指针的原生接口
	//判断原生指针是否存在
	if(p) {}
	// better   也可以拿来直接用,判断原生指针存在不存在
	if(obj) {}

	// operator -> *
	std::cout << p->id() << obj->id() << (*obj).id() << std::endl;
	print(obj);
	p = obj.release();
	delete p;

	//uniquePtr有两种reset形式,如下:
	obj.reset();
	obj.reset(new Object(2));
	/* 上面这句等价于:
	先把原有的资源释放掉obj.reset();
	然后再去管理新的指针
	*/

	//在unique_ptr中
	// UniqueObjectPtr(const UniqueObjectPtr&)   这种形式的拷贝构造函数是不存在的
	// UniqueObjectPtr(UniqueObjectPtr&&)        存在这种形式的拷贝构造函数
	//因此可以通过传入右值来
	//transfer传入的是一个unique_ptr的“值”。
	//由于unique_ptr的特性是同一时刻只能有一个unique_ptr来管理这份资源
	//因此调用transfer时,可以传入一个右值引用,这样会调用unique_ptr的传入右值的拷贝构造函数
	transfer(std::move(obj));
	
	assert(obj == nullptr);
	//std::cout << obj->id() << std::endl;

	obj.reset(new Object(4));
	//将unique_ptr转化成shared_ptr
	ObjectPtr sharedObj(std::move(obj));
	assert(obj == nullptr);
}

 

 


使用智能指针需要注意的坑

void sharedPtrNotice() {
	// 前提:绝对不要自己手动的管理资源
	/*因此下面的代码是不好的:

	第一种形式:
	int* a = new int(10);
	delete a;
	第二种形式:
	int* b = malloc(sizeof(int));

	if (b) {
		free(b);
	}
	*/

	//第一点:
	//一个裸的指针不要用两个shared_ptr管理, unique_ptr也是一样。
	//会出现资源的重复释放
	auto pObj = new Object(1);
	ObjectPtr obj(pObj);
	ObjectPtr obj2(pObj);

	//第二点:
	// 用weak_ptr打破循环引用,parent 和 child
	// 当需要在类的内部接口中,如果需要将this作为智能指针来使用的话,需要
	// 用该类派生自enable_shared_from_this

    //第三点:
	// 使用shared_ptr作为函数的接口,如果有可能有const shared_ptr&的形式
	// 多线程模式下使用shared_ptr需要注意的事项

	//第四点:
	// shared_ptr、 weak_ptr 和裸指针相比,空间上会大很多,并且效率上会有影响。
	//尤其是在多线程模式下
	//对于下面的过程,裸指针的操作是原子的。而智能指针需要先做两个引用计数加1以及一个资源的拷贝。
	//在多线程情况下,为了保证拷贝是原子安全的,还要做很多额外的操作
	ObjectPtr obj3(new Object(2));
	ObjectPtr obj4 = obj3;

	//第五点:
	//可以通过如下方法来构造智能指针
	ObjectPtr obj5 = std::make_shared<Object>(3);
	// ObjectPtr obj5(new Object(3));  这句和上面那句是等价的,但是上面那句的效率更好

	//第六点:
	//enable_shared_from_this中有一个函数——shared_from_this()(他不能在构造函数和析构函数中使用)和构造析构函数一样,
	// 某些情况下,会出现内存不会降的问题。尤其是使用weak_ptr来处理循环引用的问题
	//当某些资源已经失效了,但是weak_ptr在引用这个资源,因此该资源不能被释放,内存就因此提升了

	//第七点:
	// 如果有可能,优先使用类的实例,其次万不得已使用std::unique_ptr,
	// 万不得已使用std::shared_ptr
	Object obj6(6);
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章