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);
}

 

 

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