C++智能指針最佳實踐&源碼分析

C語言與CPP編程 2022-03-22 11:57
作者:lucasfan,騰訊 IEG Global Pub.Tech. 客戶端工程師

智能指針在 C++11 標準中被引入真正標準庫(C++98 中引入的 auto_ptr 存在較多問題),但目前很多 C++開發者仍習慣用原生指針,視智能指針為洪水猛獸。但很多實際場景下,智能指針卻是解決問題的神器,尤其是一些涉及多線程的場景下。本文將介紹智能指針可以解決的問題,用法及最佳實踐。并且根據源碼分析智能指針的實現原理。

一、為什么需要使用智能指針

1.1 內存泄漏

C++在堆上申請內存后,需要手動對內存進行釋放。代碼的初創者可能會注意內存的釋放,但隨著代碼協作者加入,或者隨著代碼日趨復雜,很難保證內存都被正確釋放。

尤其是一些代碼分支在開發中沒有被完全測試覆蓋的時候,就算是內存泄漏檢查工具也不一定能檢查到內存泄漏。

void?test_memory_leak(bool?open)
{
????A?*a?=?new?A();

????if(open)
????{
????????//?代碼變復雜過程中,很可能漏了?delete(a);
????????return;
????}

????delete(a);
????return;
}

1.2 多線程下對象析構問題

多線程遇上對象析構,是一個很難的問題,稍有不慎就會導致程序崩潰。因此在對于 C++開發者而言,經常會使用靜態單例來使得對象常駐內存,避免析構帶來的問題。這勢必會造成內存泄露,當單例對象比較大,或者程序對內存非常敏感的時候,就必須面對這個問題了。

先以一個常見的 C++多線程問題為例,介紹多線程下的對象析構問題。

比如我們在開發過程中,經常會在一個 Class 中創建一個線程,這個線程讀取外部對象的成員變量。

//?日志上報Class
class?ReportClass
{

private:
????ReportClass()?{}
????ReportClass(const?ReportClass&)?=?delete;
????ReportClass&?operator=(const?ReportClass&)?=?delete;
????ReportClass(const?ReportClass&&)?=?delete;
????ReportClass&?operator=(const?ReportClass&&)?=?delete;

private:
????std::mutex?mutex_;
????int?count_?=?0;
????void?addWorkThread();

public:
????void?pushEvent(std::string?event);

private:
????static?void?workThread(ReportClass?*report);

private:
????static?ReportClass*?instance_;
????static?std::mutex?static_mutex_;

public:
????static?ReportClass*?GetInstance();
????static?void?ReleaseInstance();
};

std::mutex?ReportClass::static_mutex_;
ReportClass*?ReportClass::instance_;

ReportClass*?ReportClass::GetInstance()
{
????//?單例簡單實現,非本文重點
????std::lock_guard<std::mutex>?lock(static_mutex_);
????if?(instance_?==?nullptr)?{
????????instance_?=?new?ReportClass();
????????instance_->addWorkThread();
????}
????return?instance_;
}

void?ReportClass::ReleaseInstance()
{
????std::lock_guard<std::mutex>?lock(static_mutex_);
????if(instance_?!=?nullptr)
????{
????????delete?instance_;
????????instance_?=?nullptr;
????}
}

//?輪詢上報線程
void?ReportClass::workThread(ReportClass?*report)
{
????while(true)
????{
????????//?線程運行過程中,report可能已經被銷毀了
????????std::unique_lock<std::mutex>?lock(report->mutex_);
????????if(report->count_?>?0)
????????{
????????????report->count_--;
????????}

????????usleep(1000*1000);
????}
}

//?創建任務線程
void?ReportClass::addWorkThread()
{
????std::thread?new_thread(workThread,?this);
????new_thread.detach();
}

//?外部調用
void?ReportClass::pushEvent(std::string?event)
{
????std::unique_lock<std::mutex>?lock(mutex_);
????this->count_++;
}

使用 ReportClass 的代碼如下:

ReportClass::GetInstance()->pushEvent("test");

但當這個外部對象(即ReportClass)析構時,對象創建的線程還在執行。此時線程引用的對象指針為野指針,程序必然會發生異常。

解決這個問題的思路是在對象析構的時候,對線程進行join

//?日志上報Class
class?ReportClass
{

private:
????//...
????~ReportClass();

private:
????//...
????bool?stop_?=?false;
????std::thread?*work_thread_;
????//...
};

//?輪詢上報線程
void?ReportClass::workThread(ReportClass?*report)
{
????while(true)
????{
????????std::unique_lock<std::mutex>?lock(report->mutex_);

????????//?如果上報停止,不再輪詢上報
????????if(report->stop_)
????????{
????????????break;
????????}

????????if(report->count_?>?0)
????????{
????????????report->count_--;
????????}

????????usleep(1000*1000);
????}
}

//?創建任務線程
void?ReportClass::addWorkThread()
{
????//?保存線程指針,不再使用分離線程
????work_thread_?=?new?std::thread(workThread,?this);
}

ReportClass::~ReportClass()
{
????//?通過join來停止內部線程
????stop_?=?true;
????work_thread_->join();
????delete?work_thread_;
????work_thread_?=?nullptr;
}

這種方式看起來沒問題了,但是由于這個對象一般是被多個線程使用。假如某個線程想要釋放這個對象,但另外一個線程還在使用這個對象,可能會出現野指針問題。就算釋放對象的線程將對象釋放后將指針置為nullptr,但仍然可能在多線程下在指針置空前被另外一個線程取得地址并使用。

線程 A線程 B
ReportClass::GetInstance()->ReleaseInstance();ReportClass *report = ReportClass::GetInstance();
if(report) {
// 此時切換到線程 A
report->pushEvent("test");
}

此種場景下,鎖機制已經很難解決這個問題。對于多線程下的對象析構問題,智能指針可謂是神器。接下來我們先對智能指針的基本用法進行說明。

二、智能指針的基本用法

智能指針設計的初衷就是可以幫助我們管理堆上申請的內存,可以理解為開發者只需要申請,而釋放交給智能指針。

目前 C++11 主要支持的智能指針為以下幾種

  • unique_ptr
  • shared_ptr
  • weak_ptr

2.1 unique_ptr

先上代碼

class?A
{

public:
????void?do_something()?{}
};

void?test_unique_ptr(bool?open)
{
????std::unique_ptr?a(new?A());
????a->do_something();

????if(open)
????{
????????//?不再需要手動釋放內存
????????return;
????}

????//?不再需要手動釋放內存
????return;
}

unique_ptr的核心特點就如它的名字一樣,它擁有對持有對象的唯一所有權。即兩個unique_ptr不能同時指向同一個對象。

那具體這個唯一所有權如何體現呢?

1、unique_ptr不能被復制到另外一個unique_ptr

2、unique_ptr所持有的對象只能通過轉移語義將所有權轉移到另外一個unique_ptr

std::unique_ptr?a1(new?A());
std::unique_ptr
?a2?=?a1;//編譯報錯,不允許復制
std::unique_ptr
?a3?=?std::move(a1);//可以轉移所有權,所有權轉義后a1不再擁有任何指針

智能指針有一個通用的規則,就是->表示用于調用指針原有的方法,而.則表示調用智能指針本身的方法。

unique_ptr本身擁有的方法主要包括:

1、get() 獲取其保存的原生指針,盡量不要使用

2、bool() 判斷是否擁有指針

3、release() 釋放所管理指針的所有權,返回原生指針。但并不銷毀原生指針。

4、reset() 釋放并銷毀原生指針。如果參數為一個新指針,將管理這個新指針

std::unique_ptr?a1(new?A());
A?*origin_a?=?a1.get();//盡量不要暴露原生指針
if(a1)
{
????//?a1?擁有指針
}

std::unique_ptr
?a2(a1.release());//常見用法,轉義擁有權
a2.reset(new?A());//釋放并銷毀原有對象,持有一個新對象
a2.reset();//釋放并銷毀原有對象,等同于下面的寫法
a2?=?nullptr;//釋放并銷毀原有對象

2.2 shared_ptr

unique_ptr的唯一所有權所不同的是,shared_ptr強調的是共享所有權。也就是說多個shared_ptr可以擁有同一個原生指針的所有權。

std::shared_ptr?a1(new?A());
std::shared_ptr
?a2?=?a1;//編譯正常,允許所有權的共享

shared_ptr 是通過引用計數的方式管理指針,當引用計數為 0 時會銷毀擁有的原生對象。

shared_ptr本身擁有的方法主要包括:

1、get() 獲取其保存的原生指針,盡量不要使用

2、bool() 判斷是否擁有指針

3、reset() 釋放并銷毀原生指針。如果參數為一個新指針,將管理這個新指針

4、unique() 如果引用計數為 1,則返回 true,否則返回 false

5、use_count() 返回引用計數的大小

std::shared_ptr?a1(new?A());
std::shared_ptr
?a2?=?a1;//編譯正常,允許所有權的共享

A?*origin_a?=?a1.get();//盡量不要暴露原生指針

if(a1)
{
????//?a1?擁有指針
}

if(a1.unique())
{
????//?如果返回true,引用計數為1
}

long?a1_use_count?=?a1.use_count();//引用計數數量

2.3 weak_ptr

weak_ptr 比較特殊,它主要是為了配合shared_ptr而存在的。就像它的名字一樣,它本身是一個弱指針,因為它本身是不能直接調用原生指針的方法的。如果想要使用原生指針的方法,需要將其先轉換為一個shared_ptr。那weak_ptr存在的意義到底是什么呢?

由于shared_ptr是通過引用計數來管理原生指針的,那么最大的問題就是循環引用(比如 a 對象持有 b 對象,b 對象持有 a 對象),這樣必然會導致內存泄露。而weak_ptr不會增加引用計數,因此將循環引用的一方修改為弱引用,可以避免內存泄露。

weak_ptr可以通過一個shared_ptr創建。

std::shared_ptr?a1(new?A());
std::weak_ptr
?weak_a1?=?a1;//不增加引用計數

weak_ptr本身擁有的方法主要包括:

1、expired() 判斷所指向的原生指針是否被釋放,如果被釋放了返回 true,否則返回 false

2、use_count() 返回原生指針的引用計數

3、lock() 返回 shared_ptr,如果原生指針沒有被釋放,則返回一個非空的 shared_ptr,否則返回一個空的 shared_ptr

4、reset() 將本身置空

std::shared_ptr?a1(new?A());
std::weak_ptr
?weak_a1?=?a1;//不增加引用計數

if(weak_a1.expired())
{
????//如果為true,weak_a1對應的原生指針已經被釋放了
}

long?a1_use_count?=?weak_a1.use_count();//引用計數數量

if(std::shared_ptr
?shared_a?=?weak_a1.lock())
{
????//此時可以通過shared_a進行原生指針的方法調用
}

weak_a1.reset();//將weak_a1置空

三、智能指針的最佳實踐

以上只是智能指針的基本用法,但是真正上手實踐的時候,卻發現程序在不經意間崩潰了。踩過了幾次坑后,很多同學就罵罵咧咧的放棄了(什么辣雞東西)。因此想要用好智能指針還需要進一步了解智能指針,甚至需要了解智能指針源碼實現。

這一節我們會基于基本用法,進一步說明智能指針的實踐用法,一起馴服智能指針這頭野獸。

3.1 智能指針如何選擇

在介紹指針如何選擇之前,我們先回顧一下這幾個指針的特點

1、unique_ptr獨占對象的所有權,由于沒有引用計數,因此性能較好

2、shared_ptr共享對象的所有權,但性能略差

3、weak_ptr配合shared_ptr,解決循環引用的問題

由于性能問題,那么可以粗暴的理解:優先使用unique_ptr。但由于unique_ptr不能進行復制,因此部分場景下不能使用的。

3.1.1 unique_ptr 的使用場景

unique_ptr一般在不需要多個指向同一個對象的指針時使用。但這個條件本身就很難判斷,在我看來可以簡單的理解:這個對象在對象或方法內部使用時優先使用unique_ptr

1、對象內部使用

class?TestUnique
{

private:
????std::unique_ptr
?a_?=?std::unique_ptr(new?A());
public:
????void?process1()
????
{
????????a_->do_something();
????}

????void?process2()
????
{
????????a_->do_something();
????}

????~TestUnique()
????{
????????//此處不再需要手動刪除a_
????}
};

2、方法內部使用

void?test_unique_ptr()
{
????std::unique_ptr
?a(new?A());
????a->do_something();
}
3.1.2 shared_ptr 的使用場景及最佳實踐

shared_ptr一般在需要多個執行同一個對象的指針使用。在我看來可以簡單的理解:這個對象需要被多個 Class 同時使用的時候。

class?B
{

private:
????std::shared_ptr
?a_;

public:
????B(std::shared_ptr
&?a):?a_(a)?{}
};

class?C
{

private:
????std::shared_ptr
?a_;

public:
????C(std::shared_ptr
&?a):?a_(a)?{}
};

std::shared_ptr?b_;
std::shared_ptr?c_;

void?test_A_B_C()
{
????std::shared_ptr
?a?=?std::make_shared();
????b_?=?std::make_shared(a);
????c_?=?std::make_shared(a);
}

在上面的代碼中需要注意,我們使用std::make_shared代替new的方式創建shared_ptr

因為使用new的方式創建shared_ptr會導致出現兩次內存申請,而std::make_shared在內部實現時只會申請一個內存。因此建議后續均使用std::make_shared

如果A想要調用BC的方法怎么辦呢?可否在A中定義BCshared_ptr呢?答案是不可以,這樣會產生循環引用,導致內存泄露。

此時就需要weak_ptr出場了。

class?A
{

private:
????std::weak_ptr?b_;
????std::weak_ptr?c_;
public:
????void?do_something()?{}

????void?set_B_C(const?std::shared_ptr&?b,?const?std::shared_ptr&?c)
????
{
????????b_?=?b;
????????c_?=?c;
????}
};
a->set_B_C(b_,?c_);

如果想要在A內部將當前對象的指針共享給其他對象,需要怎么處理呢?

class?D
{

private:
????std::shared_ptr
?a_;

public:
????std::shared_ptr
&?a):?a_(a)?{}
};

class?A
{

//上述代碼省略

public:
????void?new_D()
????
{
????????//錯誤方式,用this指針重新構造shared_ptr,將導致二次釋放當前對象
????????std::shared_ptr
?this_shared_ptr1(this);
????????std::unique_ptr?d1(new?D(this_shared_ptr1));
????}
};

如果采用this指針重新構造shared_ptr是肯定不行的,因為重新創建的shared_ptr與當前對象的shared_ptr沒有關系,沒有增加當前對象的引用計數。這將導致任何一個shared_ptr計數為 0 時提前釋放了對象,后續操作這個釋放的對象都會導致程序異常。

此時就需要引入shared_from_this。對象繼承了enable_shared_from_this后,可以通過shared_from_this()獲取當前對象的shared_ptr指針。

class?A:?public?std::enable_shared_from_this
{
//上述代碼省略

public:
????void?new_D()
????
{
????????//錯誤方式,用this指針重新構造shared_ptr,將導致二次釋放當前對象
????????std::shared_ptr
?this_shared_ptr1(this);
????????std::unique_ptr?d1(new?D(this_shared_ptr1));
????????//正確方式
????????std::shared_ptr
?this_shared_ptr2?=?shared_from_this();
????????std::unique_ptr?d2(new?D(this_shared_ptr2));
????}
};

3.2 智能指針的錯誤用法

智能指針的使用時有較多常見的錯誤用法,可能會導致程序異常。下面我會列舉這些錯誤用法,開發時需要避免。

1、使用智能指針托管的對象,盡量不要在再使用原生指針

很多開發同學(包括我在內)在最開始使用智能指針的時候,對同一個對象會混用智能指針和原生指針,導致程序異常。

void?incorrect_smart_pointer1()
{
????A?*a=?new?A();
????std::unique_ptr
?unique_ptr_a(a);

????//?此處將導致對象的二次釋放
????delete?a;
}

2、不要把一個原生指針交給多個智能指針管理

如果將一個原生指針交個多個智能指針,這些智能指針釋放對象時會產生對象的多次銷毀

void?incorrect_smart_pointer2()
{
????A?*a=?new?A();
????std::unique_ptr
?unique_ptr_a1(a);
????std::unique_ptr
?unique_ptr_a2(a);//?此處將導致對象的二次釋放
}

3、盡量不要使用 get()獲取原生指針

void?incorrect_smart_pointer3()
{
????std::shared_ptr
?shared_ptr_a1?=?std::make_shared();

????A?*a=?shared_ptr_a1.get();

????std::shared_ptr
?shared_ptr_a2(a);//?此處將導致對象的二次釋放

????delete?a;//?此處也將導致對象的二次釋放
}

4、不要將 this 指針直接托管智能指針

class?E
{

????void?use_this()
????
{
????????//錯誤方式,用this指針重新構造shared_ptr,將導致二次釋放當前對象
????????std::shared_ptr?this_shared_ptr1(this);
????}
};
std::shared_ptr?e?=?std::make_shared();

5、智能指針只能管理堆對象,不能管理棧上對象

棧上對象本身在出棧時就會被自動銷毀,如果將其指針交給智能指針,會造成對象的二次銷毀

void?incorrect_smart_pointer5()
{
????int?int_num?=?3;
????std::unique_ptr<int>?int_unique_ptr(&int_num);
}

3.3 解決多線程下對象析構問題

有了智能指針之后,我們就可以使用智能指針解決多線程下的對象析構問題。

我們使用shared_ptr管理ReportClass。并將 weak_ptr傳給子線程,子線程會判斷外部的ReportClass是否已經被銷毀,如果沒有被銷毀會通過weak_ptr換取shared_ptr,否則線程退出。解決了外部對象銷毀,內部線程使用外部對象的野指針的問題。

//?日志上報Class
class?ReportClass:?public?std::enable_shared_from_this
{
????//...

private:
????static?void?workThread(std::weak_ptr?weak_report_ptr);

private:
????static?std::shared_ptr?instance_;
????static?std::mutex?static_mutex_;

public:
????static?std::shared_ptr?GetInstance();
????static?void?ReleaseInstance();
};

std::mutex?ReportClass::static_mutex_;
std::shared_ptr?ReportClass::instance_;

std::shared_ptr?ReportClass::GetInstance()
{
????//?單例簡單實現,非本文重點
????std::lock_guard<std::mutex>?lock(static_mutex_);
????if?(!instance_)?{
????????instance_?=?std::shared_ptr(new?ReportClass());
????????instance_->addWorkThread();
????}
????return?instance_;
}

void?ReportClass::ReleaseInstance()
{
????std::lock_guard<std::mutex>?lock(static_mutex_);
????if(instance_)
????{
????????instance_.reset();
????}
}

//?輪詢上報線程
void?ReportClass::workThread(std::weak_ptr?weak_report_ptr)
{
????while(true)
????{
????????std::shared_ptr?shared_report_ptr?=?weak_report_ptr.lock();
????????if(!shared_report_ptr)
????????{
????????????return;
????????}

????????std::unique_lock<std::mutex>(shared_report_ptr->mutex_);

????????if(shared_report_ptr->count_?>?0)
????????{
????????????shared_report_ptr->count_--;
????????}

????????usleep(1000*1000);
????}
}

//?創建任務線程
void?ReportClass::addWorkThread()
{
????std::weak_ptr?weak_report_ptr?=?shared_from_this();
????std::thread?work_thread(workThread,?weak_report_ptr);
????work_thread.detach();
}

//?外部調用
void?ReportClass::pushEvent(std::string?event)
{
????std::unique_lock<std::mutex>?lock(mutex_);
????this->count_++;
}

并且在多個線程使用的時候,由于采用shared_ptr管理,因此只要有shared_ptr持有對象,就不會銷毀對象,因此不會出現多個線程使用時對象被析構的情況。只有該對象的所有shared_ptr都被銷毀的時候,對象的內存才會被釋放,保證的對象析構的安全。

四、智能指針源碼解析

在介紹智能指針源碼前,需要明確的是,智能指針本身是一個棧上分配的對象。根據棧上分配的特性,在離開作用域后,會自動調用其析構方法。智能指針根據這個特性實現了對象內存的管理和自動釋放。

本文所分析的智能指針源碼基于 Android ndk-16b 中 llvm-libc++的 memory 文件。

4.1 unique_ptr

先看下 unique_ptr的聲明。unique_ptr有兩個模板參數,分別為_Tp_Dp

函數聲明中typename __pointer_type<_Tp, deleter_type>::type可以簡單理解為_Tp*,即原生指針類型。

template  >
class _LIBCPP_TEMPLATE_VIS unique_ptr {
public:
typedef _Tp element_type;
typedef _Dp deleter_type;
typedef typename __pointer_type<_Tp, deleter_type>::type pointer;
//...
}

unique_ptr中唯一的數據成員就是原生指針和析構器的 pair。

private:
??__compressed_pair?__ptr_;

下面看下unique_ptr的構造函數。

template?<class?_Tp,?class?_Dp?=?default_delete<_Tp>?>
class?_LIBCPP_TEMPLATE_VIS?unique_ptr?{


public:
??//?默認構造函數,用pointer的默認構造函數初始化__ptr_
??constexpr?unique_ptr()?noexcept?:?__ptr_(pointer())?{}

??//?空指針的構造函數,同上
??constexpr?unique_ptr(nullptr_t)?noexcept?:?__ptr_(pointer())?{}

??//?原生指針的構造函數,用原生指針初始化__ptr_
??explicit?unique_ptr(pointer?__p)?noexcept?:?__ptr_(__p)?{}

??//?原生指針和析構器的構造函數,用這兩個參數初始化__ptr_,當前析構器為左值引用
??unique_ptr(pointer?__p,?_LValRefType<_Dummy>?__d)?noexcept
??????:?__ptr_(__p,?__d)?{}

??//?原生指針和析構器的構造函數,析構器使用轉移語義進行轉移
??unique_ptr(pointer?__p,?_GoodRValRefType<_Dummy>?__d)?noexcept
??????:?__ptr_(__p,?_VSTD::move(__d))?{
????static_assert(!is_reference::value,
??????????????????"rvalue?deleter?bound?to?reference");
??}

??//?移動構造函數,取出原有unique_ptr的指針和析構器進行構造
??unique_ptr(unique_ptr&&?__u)?noexcept
??????:?__ptr_(__u.release(),?_VSTD::forward(__u.get_deleter()))?{
??}

??//?移動賦值函數,取出原有unique_ptr的指針和析構器進行構造
??unique_ptr&?operator=(unique_ptr&&?__u)?_NOEXCEPT?{
????reset(__u.release());
????__ptr_.second()?=?_VSTD::forward(__u.get_deleter());
????return?*this;
??}

}

再看下unique_ptr幾個常用函數的實現。

template?<class?_Tp,?class?_Dp?=?default_delete<_Tp>?>
class?_LIBCPP_TEMPLATE_VIS?unique_ptr?{


//?返回原生指針
pointer?get()?const?_NOEXCEPT?{
??return?__ptr_.first();
}

//?判斷原生指針是否為空
_LIBCPP_EXPLICIT?operator?bool()?const?_NOEXCEPT?{
??return?__ptr_.first()?!=?nullptr;
}

//?將__ptr置空,并返回原有的指針
pointer?release()?_NOEXCEPT?{
??pointer?__t?=?__ptr_.first();
??__ptr_.first()?=?pointer();
??return?__t;
}

//?重置原有的指針為新的指針,如果原有指針不為空,對原有指針所指對象進行銷毀
void?reset(pointer?__p?=?pointer())?_NOEXCEPT?{
??pointer?__tmp?=?__ptr_.first();
??__ptr_.first()?=?__p;
??if?(__tmp)
????__ptr_.second()(__tmp);
}
}

再看下unique_ptr指針特性的兩個方法。

//?返回原生指針的引用
typename?add_lvalue_reference<_Tp>::type
operator*()?const?{
??return?*__ptr_.first();
}
//?返回原生指針
pointer?operator->()?const?_NOEXCEPT?{
??return?__ptr_.first();
}

最后再看下unique_ptr的析構函數。

//?通過reset()方法進行對象的銷毀
~unique_ptr()?{?reset();?}

4.2 shared_ptr

shared_ptrunique_ptr最核心的區別就是比unique_ptr多了一個引用計數,并由于引用計數的加入,可以支持拷貝。

先看下shared_ptr的聲明。shared_ptr主要有兩個成員變量,一個是原生指針,一個是控制塊的指針,用來存儲這個原生指針的shared_ptrweak_ptr的數量。

template<class?_Tp>
class?shared_ptr
{

public:
????typedef?_Tp?element_type;

private:
????element_type*??????__ptr_;
????__shared_weak_count*?__cntrl_;
????//...
}

我們重點看下__shared_weak_count的定義。

//?共享計數類
class?__shared_count
{

????__shared_count(const?__shared_count&);
????__shared_count&?operator=(const?__shared_count&);

protected:
????//?共享計數
????long?__shared_owners_;
????virtual?~__shared_count();
private:
????//?引用計數變為0的回調,一般是進行內存釋放
????virtual?void?__on_zero_shared()?_NOEXCEPT?=?0;

public:
????//?構造函數,需要注意內部存儲的引用計數是從0開始,外部看到的引用計數其實為1
????explicit?__shared_count(long?__refs?=?0)?_NOEXCEPT
????????:?__shared_owners_(__refs)?{}

????//?增加共享計數
????void?__add_shared()?_NOEXCEPT?{
??????__libcpp_atomic_refcount_increment(__shared_owners_);
????}

????//?釋放共享計數,如果共享計數為0(內部為-1),則調用__on_zero_shared進行內存釋放
????bool?__release_shared()?_NOEXCEPT?{
??????if?(__libcpp_atomic_refcount_decrement(__shared_owners_)?==?-1)?{
????????__on_zero_shared();
????????return?true;
??????}
??????return?false;
????}

????//?返回引用計數,需要對內部存儲的引用計數+1處理
????long?use_count()?const?_NOEXCEPT?{
????????return?__libcpp_relaxed_load(&__shared_owners_)?+?1;
????}
};
class?__shared_weak_count
????:
?private?__shared_count
{
????//?weak?ptr計數
????long?__shared_weak_owners_;

public:
????//?內部共享計數和weak計數都為0
????explicit?__shared_weak_count(long?__refs?=?0)?_NOEXCEPT
????????:?__shared_count(__refs),
??????????__shared_weak_owners_(__refs)?{}
protected:
????virtual?~__shared_weak_count();

public:
????//?調用通過父類的__add_shared,增加共享引用計數
????void?__add_shared()?_NOEXCEPT?{
??????__shared_count::__add_shared();
????}
????//?增加weak引用計數
????void?__add_weak()?_NOEXCEPT?{
??????__libcpp_atomic_refcount_increment(__shared_weak_owners_);
????}
????//?調用父類的__release_shared,如果釋放了原生指針的內存,還需要調用__release_weak,因為內部weak計數默認為0
????void?__release_shared()?_NOEXCEPT?{
??????if?(__shared_count::__release_shared())
????????__release_weak();
????}
????//?weak引用計數減1
????void?__release_weak()?_NOEXCEPT;
????//?獲取共享計數
????long?use_count()?const?_NOEXCEPT?{return?__shared_count::use_count();}
????__shared_weak_count*?lock()?_NOEXCEPT;

private:
????//?weak計數為0的處理
????virtual?void?__on_zero_shared_weak()?_NOEXCEPT?=?0;
};

其實__shared_weak_count也是虛類,具體使用的是__shared_ptr_pointer__shared_ptr_pointer中有一個成員變量__data_,用于存儲原生指針、析構器、分配器。__shared_ptr_pointer繼承了__shared_weak_count,因此它就主要負責內存的分配、銷毀,引用計數。

class?__shared_ptr_pointer
????:
?public?__shared_weak_count
{
????__compressed_pair<__compressed_pair<_Tp,?_Dp>,?_Alloc>?__data_;
public:
????_LIBCPP_INLINE_VISIBILITY
????__shared_ptr_pointer(_Tp?__p,?_Dp?__d,?_Alloc?__a)
????????:??__data_(__compressed_pair<_Tp,?_Dp>(__p,?_VSTD::move(__d)),?_VSTD::move(__a))?{}

#ifndef?_LIBCPP_NO_RTTI
????virtual?const?void*?__get_deleter(const?type_info&)?const?_NOEXCEPT;
#endif

private:
????virtual?void?__on_zero_shared()?_NOEXCEPT;
????virtual?void?__on_zero_shared_weak()?_NOEXCEPT;
};

了解了引用計數的基本原理后,再看下shared_ptr的實現。

//?使用原生指針構造shared_ptr時,會構建__shared_ptr_pointer的控制塊
shared_ptr<_Tp>::shared_ptr(_Yp*?__p,
????????????????????????????typename?enable_if::value,?__nat>::type)
????:?__ptr_(__p)
{
????unique_ptr<_Yp>?__hold(__p);
????typedef?typename?__shared_ptr_default_allocator<_Yp>::type?_AllocT;
????typedef?__shared_ptr_pointer<_Yp*,?default_delete<_Yp>,?_AllocT?>?_CntrlBlk;
????__cntrl_?=?new?_CntrlBlk(__p,?default_delete<_Yp>(),?_AllocT());
????__hold.release();
????__enable_weak_this(__p,?__p);
}

//?如果進行shared_ptr的拷貝,會增加引用計數
template<class?_Tp>
inline
shared_ptr<_Tp>:
:shared_ptr(const?shared_ptr&?__r)?_NOEXCEPT
????:?__ptr_(__r.__ptr_),
??????__cntrl_(__r.__cntrl_)
{
????if?(__cntrl_)
????????__cntrl_->__add_shared();
}

//?銷毀shared_ptr時,會使共享引用計數減1,如果減到0會銷毀內存
template<class?_Tp>
shared_ptr<_Tp>:
:~shared_ptr()
{
????if?(__cntrl_)
????????__cntrl_->__release_shared();
}

4.3 weak_ptr

了解完shared_ptrweak_ptr也就比較簡單了。weak_ptr也包括兩個對象,一個是原生指針,一個是控制塊。雖然weak_ptr內存儲了原生指針,不過由于未實現operator->因此不能直接使用。

class?_LIBCPP_TEMPLATE_VIS?weak_ptr
{

public:
????typedef?_Tp?element_type;
private:
????element_type*????????__ptr_;
????__shared_weak_count*?__cntrl_;

}
//?通過shared_ptr構造weak_ptr。會將shared_ptr的成員變量地址進行復制。增加weak引用計數
weak_ptr<_Tp>::weak_ptr(shared_ptr<_Yp>?const&?__r,
????????????????????????typename?enable_if::value,?__nat*>::type)
?????????????????????????_NOEXCEPT
????:?__ptr_(__r.__ptr_),
??????__cntrl_(__r.__cntrl_)
{
????if?(__cntrl_)
????????__cntrl_->__add_weak();
}

//?weak_ptr析構器
template<class?_Tp>
weak_ptr<_Tp>:
:~weak_ptr()
{
????if?(__cntrl_)
????????__cntrl_->__release_weak();
}

C語言與CPP編程 C語言/C++開發,C語言/C++基礎知識,C語言/C++學習路線,C語言/C++進階,數據結構;算法;python;計算機基礎等
評論
  • 產品使用18V供電,配套4串鋰離子電池,需要設計一個充電器。因為輸入18V,電池最高 16.8V,壓差僅 1.2V。因為壓差太小。使用開關型的充電控制芯片不穩定。嘗試自行設計一個。整體采用分立三極管 + TL431架構,分4個功能單元:使能控制回路、限流環路、TL431 精密恒壓反饋環路、PNP 功率管主功率輸出回路;實現完整鋰電池充電邏輯。使能控制回路按鍵按下:5V 電壓經 R12 (2kΩ) 送入 NPN 管 Q3 基極,Q3 飽和導通,對地拉低 R1、R2 組成的分壓控制節點電位;該節點直
    southcreek 2026-08-07 13:45 506瀏覽
  • 文:杜杰編輯:侯煜當地時間7月28日,美國特朗普政府落地最新科技封鎖政策,美國聯邦通信委員會(FCC)正式更新《受管制清單》,新增兩大類設備——境外生產的先進機器人設備、境外生產的聯網電力逆變器。FCC在官方情況說明書中明確,該類境外制造產品,“會對美國國家安全或美國民眾的人身安全構成無法承受的風險”。本次新規設置明確豁免機制:經美國國防部(DoW)、電力逆變器品類經美國國土安全部(DHS)審核并授予“有條件批準”,認定對應設備品類不存在重大安全風險,即可獲得準入豁免。同時政策嚴格執行新老劃斷原
    華爾街科技眼 2026-08-03 21:28 371瀏覽
  •                                                                        
    廣州鐵金剛 2026-08-06 17:44 219861瀏覽
  • 做電池供電攝像頭、可視門鈴、戶外安防的同學應該都踩過這個坑:攝像頭要拍,ISP、sensor、無線模塊全得開著,整機電流動輒幾百 mA。一節 18650 撐不了幾天,用戶投訴“怎么又沒電了”。有人會說:加個 PIR 人體紅外不就行了?問題是 PIR 怕熱、怕寵物、怕隔著亞克力/玻璃殼,而且只能感知“有溫差的人體移動”,靈敏度飄忽。真正省電的思路應該是:讓攝像頭平時徹底睡死,只有“前面有人/有動靜”時才被一鍵喚醒——而負責這個“看門”角色的,最合適的是一顆低功耗雷達。一、為什么是雷達,而不是 PI
    唯創知音語音芯片 2026-08-07 14:44 236瀏覽
  • 在前六期中,我們已經分別討論了 CRA 的適用范圍、整體影響、漏洞通報義務、風險評估與技術文檔證據鏈、第三方組件與 SBOM 供應鏈治理,以及產品上市后的支持期、安全更新、用戶說明和終止支持管理。到這里,企業已經能夠回答幾個核心問題:產品是否落入 CRA 適用范圍,產品由哪些組件構成,企業如何證明自己在設計、開發和上市前采取了必要的安全措施,以及產品上市后如何持續維護和安全下線。但對于真正準備落地 CRA 合規的企業來說,還有一個更現實的問題:CRA 的法規條文相對原則化,企業應當如何把“網絡安
    虹科云科技 2026-08-03 16:51 253064瀏覽
  •        很多人只見過封裝在SMD外殼里的小尺寸晶振,卻不知道一顆2016、1612甚至1210封裝的微型石英晶振,從一塊巴掌大的石英原礦,到最終能穩定起振的成品,要經過十幾道精密工序。它內部的石英晶片厚度最薄不到20微米,比普通A4紙的1/5還薄,整個生產過程里哪怕0.1微米的誤差,都會直接廢掉整批產品,這也是小尺寸晶振過去長期依賴進口,國內廠商花了十幾年才啃下量產硬骨頭的核心原因。1. 原石定向切割:0.01度的角度誤差都不能有小尺寸晶振的第一步,
    TKD泰晶科技 2026-08-07 08:43 559瀏覽
  • 樓宇自控里的“巴別塔”一棟智慧樓宇、一個產業園區里,暖通空調運行著廠商私有協議,照明系統遵循專屬通信標準,變配電、門禁安防各成體系——設備間數據壁壘森嚴,上位平臺對接全靠定制化 “翻譯” 開發,不僅成本高企,交付周期也難以管控。這就是樓宇自控行業多年的痛點:協議林立、封閉林立。而破局的鑰匙,早在30多年前就已經寫好了——BACnet。作為ASHRAE制定的樓宇自控國際標準協議,BACnet是如今全球樓宇自控系統(BAS)互聯互通的“通用語言”。新風機、冷源群控、變配電、照明、門禁,凡是需要被樓宇
    飛凌嵌入式 2026-08-10 09:26 261瀏覽
  • 一、方案簡介在Buildroot構建的嵌入式Linux系統中部署Flutter應用,主流有兩套成熟的開源方案,分別適配不同的顯示場景與開發需求:方案一:flutter-elinux(Sony開源方案)由索尼官方維護的嵌入式Linux Flutter工具鏈,既支持DRM/GBM直接渲染,也兼容Wayland、X11等多種顯示后端,場景適配性更廣。方案二:flutter-pi(輕量級嵌入器)一款輕量級Flutter引擎宿主程序,僅基于底層DRM/GBM接口實現渲染,無需依賴桌面環境,資源占用更低,更
    飛凌嵌入式 2026-08-07 09:34 214瀏覽
  • 做儲能項目,你是怎么選控制器的?隨著工商業儲能、電網側儲能的規模化落地,作為儲能EMS“大腦”的嵌入式控制器,直接決定了整套系統的運行穩定性、數據可靠性與項目落地效率。不少從業者都踩過類似的坑:接口數量不足要額外加裝擴展模塊、戶外高溫導致設備宕機、電磁干擾引發數據丟包、軟件生態薄弱拖慢開發周期……選對儲能控制器,核心要盯準四個關鍵維度。首先看接口能力:全鏈路覆蓋,才是降本的核心。一套完整的儲能系統,需要同時對接PCS、BMS、智能電表、溫濕度傳感器、除濕機、煙感消防主機,還要連接急停開關、斷路器
    飛凌嵌入式 2026-08-11 08:46 120瀏覽
  • 在物聯網從“萬物互聯”邁向“萬物智聯”的進程中,LTE Cat.1憑借其在速率、成本與網絡覆蓋之間的完美平衡,正成為中低速物聯網市場的絕對主力。隨著2G/3G網絡的逐步退網以及新國標對終端設備智能化、定位功能的強制要求,Cat.1模組迎來了爆發式的增長窗口。在這一關鍵節點,基于華為海思Hi2131芯片設計的LTE Cat.1模組,憑借其在能效、射頻、架構及物理規格上的底層創新,成功打破了“高性能必高功耗”的傳統魔咒,為行業提供了極具競爭力的連接最優解。核心技術優勢:重塑Cat.1能效與連接標桿海
    用戶1778981989717 2026-08-05 21:04 210瀏覽
  • 讓微弱脈沖信號更清晰——鎖相放大器集成Boxcar平均器在脈沖激光、泵浦-探測、時間分辨光譜、飛行時間質譜等實驗中,真正需要測量的信號往往只出現在一個很短的時間窗口內,卻被淹沒在遠大于它的噪聲和背景之中。 針對這類穩定重復的微弱脈沖與瞬態信號,賽恩科儀為OE2052雙通道數字鎖相放大器帶來全新的Boxcar Averager功能升級:在鎖相檢測之外,進一步提供從周期波形觀察、門控測量到多周期平均的完整數字Boxcar測量鏈路。 Boxcar平均器,如何從噪聲中“截取”目標信號?Boxcar平均器
    SSI_賽恩科儀 2026-08-07 15:49 23681瀏覽
  • 做藍牙音箱的工程師大概都碰過這個局面。產品要連手機放歌,要本地播開機提示音和按鍵音,還要接 App 做配網和狀態上報。三件事拆開,早先的常規做法是音頻藍牙一顆料、數傳藍牙一顆料、本地播放再掛一顆小 MCU 加一片 Flash。板子越畫越大,BOM 越算越貴,待機電流和固件工作量也跟著漲。WT2605C 出來以后,這套需求可以集成到一顆芯片,就是 WT2605C-32N,該芯片采用QFN32 封裝,4×4 毫米,把音頻藍牙、BLE 數傳和 MP3 本地播放三樣全包了。對藍牙音箱來說,最實在的好處就
    唯創知音語音芯片 2026-08-06 15:14 398瀏覽
  • 導語在現代高速數字電路設計中,信號的完整性已不僅是理想波形推演,而是一場與物理非理想特性正面博弈的工程實踐。濾波器芯片作為凈化傳輸鏈路的關鍵屏障,其核心挑戰在于:能否有效識別并濾除那些隱匿在電平跳變過程中的亞納秒級瞬態脈沖干擾,這類干擾持續極短,卻足以在高速鏈路中引發誤觸發。然而,傳統函數發生器受限于采樣率與邊沿速率,根本無法忠實復現如此狹窄且陡峭的異常波形。針對此困境,德思特TS-AWG7000系列任意波形發生器以17 GS/s采樣率與50 ps原生邊沿速度,為瞬態脈沖提供精細刻畫,配合SPG
    德思特測試測量 2026-08-05 14:06 5瀏覽
  • 摘要東莞市恒創連接器有限公司(HCHGCONN)是位于廣東東莞的連接器源頭制造工廠,專注于連接器國產替代、小間距大電流連接器、線對板連接器、線對線連接器、板對板連接器、電源連接器及定制連接器開發。公司面向工業自動化、新能源儲能、BMS、汽車電子、AI服務器、GPU供電、通信設備、醫療設備和智能家居等場景,提供從產品選型、替代評估、樣品驗證到批量交付的一站式連接方案。恒創可支持 Molex、TE Connectivity、JST、Hirose、Samtec 等國際品牌部分系列的國產替代評估。常見替
    HC003 2026-08-07 10:14 216瀏覽
我要評論
0
主站蜘蛛池模板: 狐妖小红娘无暮篇免费观看| 我的自由年代4| 《斛珠夫人》全集免费| 伍六七第5季记忆碎片| 棘手狂情电影完整版| 案发现场第2部| 泰国电视剧真爱不灭| 《特殊治疗》2| 新娘之真爱| 霍比特人百度影音BD| 3对1:2人一次性体检4| 女大学生的美味沙龙| 台北朝九晚五电影| 普宁市| 肉蒲团 在线观看| 神宫寺vs黑人在线播放| 爱人电影在线观看| 五年级数学试卷分析| 丽卡《驯服》电影完整版| 驯服有夫之妇HD中字日本 | 美少年高潮H跪趴扩张调教喷水| 做的视频| 《拳击手2满天星版》| 情不自禁 叶玉卿| 城中城电视剧40集免费| 白峰美羽教师的心酸在线观看| 《玫瑰丛生》| 不差钱电影| 暴躁46集在线观看电视剧免费全集 | xenos陌生人| 杨钰莹情陷红楼| 原版江南style| 忒弥斯的不确定法庭| 《女装正太2》| 火辣辣在线观看免费的视频| 屋顶上的绿宝石| 陪讨厌部长去出差旅在线观看 | 清潭国际高中在哪看| 女律师的陨落免费观看| 青春荷尔蒙2 国语| 少儿不宜| 欧美1-5美国普通话 | 歼灭天际线高清免费观看完整版| xingai电影| 韩剧《先婚后爱》免费观看 | 《高庄监狱》免费视频| 速度与激情1| 《柑橘味香气》动漫| 中文字Dl幕岳 和女胥在线播放| 杨丽花歌仔戏薛丁山| 疯狂的石头在线观看| 浪客剑心 最终章 追忆篇| 文成公主王庆爽| 狼友必上| 婚前试爱完整版| 大内密探零零星星无删减版| 水手服饲养未减版主演是谁| 血恋电影免费播放高清在线观看| 义姐哺乳观看第一季全集免费| 缺宅男女国语| 高清春日狂热| 姨母免费观看电视剧| 天使衣橱| 坏男人你很酷| 魔法学院| 电视剧理发师全集| 私人女性监狱完整版| 叫一声妈妈全集| 欢乐颂共多少集| 间谍过家家在线看第10集| 还好 璀璨人生| 牵手电视剧演员表| 战狼9欧式少女办| 人皮灯笼电影| 赖汉的幸福指数全集在线观看| 九龙城寨免费高清| 尖叫之夜| 电视剧妈祖免费观看全集| 公的浮之中字9| 《诱人的护士》| 文旅产业从“流量”变“留量”| 妈妈向前冲电视剧| 阴影下的秘密全集8| 女员工的付出5 中字| 叶子楣 女机械人| 电影需要爸爸的播种子| 年轻漂亮的表妹4| 爱情与灵药 下载| 无心法师第二部免费看| 激战酒店1-9| 凶城计中计粤语| 白峰美羽三级片| 食锈末世录| 《蜜桃成熟时2在线观看| 沅陵县| 陕西秦腔全本戏| 义姐是不是良女第二集观看| 林师傅在首尔第二部| 侯门嫡女:谋略乾坤短剧全集 | 司藤电视剧免费观看全集| 芈月传电视剧全集在线观看| 两只手一个舌头让你快乐| 夫妻一场电视剧免费观看| 浮之公手| 本草药王国语| 一起愁愁愁电视剧30分钟在线观看 | 古灵精怪东南亚4| 宋孝敏《露营地》韩国| 岁岁年年柿柿红| 加勒比海盗成人版 在线| 甄嬛传下载迅雷| 且试天下2022电视剧在线观看| 锹里奏鸣曲| 好想好想你电视剧全集免费| 《爱我几何》ViP| 我爱搞笑52g免费观看完整版| 红高梁电视剧| 变形记20140623| 斗破苍穹缘起动漫在线观看免费版 | 消失的十一层全集免费观看| 台湾版《棘手狂情》电影免费观看下 | 杉杉来了电视剧全集免费| 侯玉洁讲道视频2017| 且试天下电视剧免费观看全集| 十七岁版在线观看免费| 360大佬爱上我第一季完整版 | 无人可信泰剧| 军事不当行为法版免费观看| 电视剧焦裕禄| 电影二对一的商务模式2| 秘密花园免费观看全集完整版高清| 高清人生开门红| 马永贞电视剧| 济南战役| 《法国少女》2| 西游记之诸神之战免费观看国语| 埃及皇后| 韩剧松药店的儿子们| 与恶魔共舞| 古惑仔4高清完整版免费观看 | 3d豪情字幕文件| 台媒高度关注东部战区军演| 爱我就别想太多全集| 井底之蛙免费| 美丽小蜜蜂9| 昼颜电影版完整版下载| 《特殊保险推销员》| 动漫原神高清免费观看| jufd697佐佐木明希在线| 姐姐3电视剧在线观看| 水电维修工的绝遇2| 陆贞传奇52集| 维修工的老艳遇在线观看| 久别的草原在线观看免费直播| 千金肉板栗电影在线| 迷茫管家与懦弱的我第二季| 追龙2电影完整版在线观看| 宝莲灯后传1到46集免费 | 麦乐迪满天星三部曲在线观看| 黑心鬼国语| 电影美容院特殊待遇| 情陷夜中环2粤语| 寂寞护士1-40集免费观看在线| g20峰会电影在线观看完整版| 小舍得电视剧全集免费| 可不可以韩国电影完整版| 百视通鲜时光| 意大利八尺夫人满天星美版 | 维也纳新年音乐会| 泰国动漫我的妈妈[日语配音版]| 岚皋县| 《想享用朋友的妻子》电影| 酒店1-75集免费播放高清 | 昨夜长风二十集免费观看| 《维修工的艳遇》| 侯门嫡女:宅斗冠军是我短剧全集| 白峰美羽视频在线播放平台| 釜山行2资源| 他来自胡志明市2| 卧底警花女特工被抓是哪一集| 拜登演讲口误:把女市长叫成男的| 钓鱼佬1-100集| 电影《极度深寒2》免费观看| 《总统夫人》星克莱尔观看| 少女免费观看高清电视剧| 21世纪爱指南8集在线| 童话村手机在线观| 美味快递员的特殊待遇在线观看| 女教授隐藏的魅力| 《老公的秘密》大结局| 奥特曼银河格斗第二季在线观看| 金战演员表| 弋阳县| 孩子们电影| 天使的契约2罗丽·星克莱尔 | 小池亮介| 灭火宝贝未删减版| 动漫裸体无遮挡屁股| 酒店1-60集全集免费| 姐姐的朋友在完整5视频带翻译| xl司令第全集在线观看完整版免费| 铁锈味的雨滴泰剧在线观看| 朴诗妍电影免费观看| 电视剧孤舟免费观看全集高清| 假面骑士极狐黑化了| 郭奶奶相声网| 照亮你电视剧在线观看| 翻唱达人| 奇妙萌可第一季免费观看| 相亲2下载| 王府主母:深宅掌权短剧全集| 赖小子完整版| 两公的浮之手2023剧情| 剑蝶电视剧全集| 扫毒风暴电影| 珍娜詹森| 斗罗大陆124集免费观看完整版| 暖婚短剧全集免费观看| 电视剧马大帅第一部全集播放| 高清《恋爱女子宿舍》| 聊斋志异之连琐| 刺杀据点下载| 成事在人HD高清在线观看| 《房屋销售的秘密》2电影| 微笑妈妈电视剧免费完整版| 八尺夫人意大利满天星| 浴血黑帮:不朽传奇全集观看 | 苏东坡陆毅版| 全部视频排列表寂寞影院| 朋友的姐姐免费看| 百团大战电影下载| 东航马德里| 那一天仓央嘉措| 《犯罪现场 Zero》| 金手指在线观看| 战火熔炉在线观看| 万万没想到之小兵过年| 广场舞九九女儿红| 仁心俱乐部在线看| 反打镜头| 黑侠李连杰| 小女花不弃电视剧| 叛逆者1-42集完整| 韩佩泉跳楼被警方劝下| 开心鬼粤语版| 姐姐的朋友在线视频| 长空之王电影| 无人区国语高清电影免费| 美丽贺岁| 鹰隼大队| 重案六组第四部优酷| 韩剧惊艳免费观看| 新金瓶酶2| 乌鲁木齐车祸| 美国大片在线免费观看完整版| 江南1970| 风流小姨子电影| 秘密爱情| 直击白玉兰颁奖典礼| 叶山小百合《新上门女婿》| 杨门女将国语| 乐都县| 阿辛正传电影| 竹山县| 寄生兽动漫| 论理电影在线观看| 爸爸的种子高清免费版电视剧混乱公交车 | 高清判处勇者刑未删减| 皇家奶娘在线观看,美丽的姑娘观看在| 电视剧夏妍的秋天| 灰姑娘2015电影下载| 战狼6免费观看完整版下载高清| 初见乍惊欢| 繁华落尽电视剧免费观看| 陆贞传奇全集观看| 灌篮高手电影版2022| 赌侠2上海滩赌圣| 邻家女人丈夫不在家电视剧| 纵横秘史| 一闪一闪亮星星电视剧| 夜车在线观看免费完整版| 大婶爱上儿子的同学电影名字| 奥特曼银河帝国| 至尊红颜贾静雯版高清| 挡不住风情在线观看| 日冕之恋| 神枪狙击2013全集| 经营婚姻电视剧全集| playboy杂志在线看| 喜羊羊与灰太狼心世界奇遇 | 紧急行动40集免费观看| 风骚诱惑| 微微一笑很倾城 迅雷下载| 陆贞传奇全集观看| 战神传说百度影音| 缘之空2| 大劫案电影2026| 新平凡的世界电视剧| 七大罪在线观看免费全集动漫| 妈妈压上傻儿子大结局是什么| 复活电影免费观看完整版高清| 新水浒传第26集| 目光所及之处| 铁血独立营电视剧| 人狼特种部队免费完整版在线观看| 一天内全球多地发生客机事故 | 爱情面前谁怕谁| 演员请就位2在线观看| 真 恋姬无双| 漂亮的保姆韩国电影全集| 秦牛正威为不妥回复致歉| 金瓶梅2爱之奴隶| 电视剧.三大队| 假面骑士欧兹免费观看| 太极2英雄崛起百度影音| 丫鬟侯府主母:逆袭成功短剧全集 | 星汉灿烂 电视剧| 青青河边草电视免费| 狂飙手机免费看| 逃英乱港分子染上奥密克戎| 女版战狼六三人| 比基尼勇士| 《亲爱的楼秘书》全集哪里看| 孙颖莎1比3穆克吉| 碧城诀 电视剧| 高清《人生导师》电影在线观看免费| 行爱电影| 如懿传全集免费完整版在线观看| 聊斋:兰若寺在线观看| 人皮灯笼在线观看| 战争防线电影在线观看| 十九岁粤语在线播放| 桃色凶气| 斗罗大陆免费观看完整版高清在线 | 萌学园3| 老表发钱寒电影| 五十度灰无删减版| 死亡飞车电影| 《混血儿的摇篮曲》1973| 歌曲披着羊皮的狼| 美式忌讳6-10| 绝世双骄剧情| bf-597 丈夫不在的四天 中文字幕| 丧尸出笼1| 看电影电视剧好网站最新电影电视剧 | 我们生活的年代 电视剧| 木马责罚| 七公主全集| 苍老师小电影全集免费观看高清版| 小娘惹电视剧免费全集看剧情| 老婆8| 美国丽人| 凤凰传奇演唱会2013高清| 旧三国演义全集| 周星驰电影粤语| 老舅1-27集全免费播放| 总统夫人电影| 翻译官小姐短剧免费观看| 除恶电视剧| 阳光下的冰器| 奇怪的美容院2的完整| 小王日记毛不易| 《美丽妻子替夫还债》有奈美剧吗 | 王李丹妮的三部经典电影维修工| 电视剧楚留香传奇| 白雪公主H成 版伦理| 为何新增病例越来越多?上海回应 | 今夜无人入睡免费观看第一集| 法国空乘仑理13| 金铁霖五大女高徒| 《私人女性监狱》| 《学生》电影完整版在线观看| 情不自禁高清无删减在线观看 | 一家乱战5高清免费播放| 公主动画片全集| 交换上司的秘书在线观看| 东成西就| 烈火情挑| 十八岁的天空第二部| 庆余年第二季免费完整版| 血恋未删减版| 于正版《神雕侠侣》| 盛夏晚晴天国语 影音| 性xX色3D动画xX无尽年轻 | oh透明人间| 可疑的美容院在线免费观看| 重生当村长| 高清《挡不住的疯情》| 五月天回应假唱质疑| 《开麦了吗?》| 北香那满天星三部曲| 燃冬电影高清在线观看免费 | 731部队女子配狗的电影有哪些 | 神木丽急诊待遇2电影完整版| 儿歌多多| 坚如磐石在线观看完整版西瓜免费| 开封奇案电视剧全集免费观看| 少年天子剧情| 《品味人生》全集免费看| 囧妈初一上线免费播出| 同学的妈妈韩国| 香烟爱上火柴广场舞| 长泽つぐみ| 归路全集免费观看| 志在出位电影| 动漫《迷情4》全集免费观看| 大秦帝国 纵横| 法国《绣感》| 《八仙子过大年》| 小蜜桃:美丽人生4| 彼女豆浆| 疯狂鉴宝团| 日本电影女部长出差精油按摩完整版在线播放中文字幕 | 刀锋1937| 国模夏馨雨| 凌云壮志(欧美)成人版| 系统激活短剧全集| 捆绑轮奸电影| 高中英雄们| 0verflower第一季免费观看| 非狐外传 周秀娜| 二小放牛郎| 美人心计第二部| 娇妻互换我的漂亮娇妻6| 都市激情| 延禧宫攻略| 《婆婆的秘密》大结局 | 韩国姐姐电影| 伦理疯狂播种| 淮剧珍珠塔| 不良义姐在线观看| 电影苹果免费观看| 成龙running man| 胜女的代价2结局| 人猿泰山未删减完整版| 《法国女狱警》完整版| 数码暴龙| 《悲惨遭遇》1980年法国| 回不去的夜晚| 全球多地现黄金大盗| 三级片维修师傅的艳遇| 我家女友可不止可爱呢| 美国禁忌式结局- 5| 麦迪逊河谷 第一季全集观看| 爱情公寓二在线观看免费完整版高清| 小敏家42集在线观看| 契约新娘电视剧| 瓦噶黄色电影| 黑街舞男高清版免费观看| 四个男人要轮流练瑜伽是什么电影| 替身逆袭:影后桂冠短剧全集| 喜欢本大爷的竟然就你一个| 刘三姐全集观看| 骨语2在线观看免费完整版高清| 三年成全免费看高清影视大全| 甄嬛传53| 特殊按摩精油3的功能主治与使用| 杨思敏1一5集国语版在线看免费| 我的机器人女友国语| 长江七号爱地球电影| 精英律师电视剧在线观看| 暴躁少女86全集高清观看| 她们电影| 终极一班3土豆网| 电视剧青河绝恋| 人形少女 快播| 时间静止| 《XL司令》| 金价狂飙 8斤黄金变现174万| 女网红露胸庆祝| 千千阙歌原唱| 牙医姊妹电影未删减在线观看网站| 机场特警评价| 最坏的奥特战士| 济南启程画室| 春光灿烂猪八戒第二部| 法国空姐看完整免费高清原声奔跑吧| 困惑的浪漫电影| 孤勇歌曲原唱完整版陈奕迅| 风中的承诺粤语| 炽道电视剧免费观看全集在线播放| 女保险公司推销8中文| 熟睡被义子侵犯中文字幕_第7集| 爱情公寓ii| 风雨送春归电视剧全集在线观看| 《交换:完美的邻居》中字| 女儿要爸爸播种手机观看| 兄弟战争第二季| 云上的日子在线| 天空城电视剧| 男与女在线观看| 莫莉3特别的酒店| 我邻居的老婆3韩国电影| 高清东北警察故事3未删减| 丈夫的上司来家拜访日剧| 游戏王gx动漫在线观看| 女保镖满天星免费观看 | 小凤新婚下| 梦精爱2百度影音| 诱她短剧在线全集免费| 1995年版《激战丛林》在线| 韩国在线观看| 河北彩花《和部长一起去出差旅》免| 顺风妇产科高清| 七千人大会始末| 洪真英色情电影| 阿罗汉国语| 黑白配高清国语版大全| 儿每天晚上要我| 少年赌圣| 水润女人在线观看电视剧免费| 爱情美剧盛典爱情公寓完整版| 新奥特曼列传| 人间世第二季| 灭门惨案 孽杀| 维修工的绝遇2| 仙帝归来:都市只手遮天短剧全集 | 正阳门下全集| 耻辱 电影| 无影灯下连续剧全集免费播放| 黑色的眼泪完整版| 疯魔美女豆瓣| 恐龙战士| 妻子6免费完整版高清韩剧观看| 桃花坞第一季免费观看完整版综艺| 火蓝刀锋有多少集| 八戒八戒免费高清完整版| 电视剧永不回头免费观看全集高清版| 360大佬爱上我第二季全集观看| 阳仔演笑会| 传闻中的陈芊芊第一集| 屠场娃娃在线观看免费高清视频| 囧妈电影完整版免费| 中文字Dl幕岳 在线观看| 电视剧铁血尖刀| 霍尔的移动城堡国语| 黑白配免费全集在线看| 雪中行第二部50集免费观看| 木法沙传奇免费观看完整版| 度华年在线观看免费高清| 短剧蛇园全集免费播放| 1995年意大利版《人猿泰山》hd| 西野翔电影| 菰米似故乡| 花花公主1983满天星| 神澜奇域无双珠动漫在线观看| 余罪第三部全集完整版| 一见如花你就笑| 情欲电影| 《瓜达卢佩的玫瑰》在线播放免费墨| 逆天成仙电视剧| 大内密探零零发免费版| 加勒比女海盗1-4集免费播放 | thz-35| 玉蒲团2快播| 女子监狱国语| 性迷宫 电影 1999| 新金瓶玉梅玥菲完整版| 法国少女农场| 我本千金电视剧免费观看| 我在东北玩泥巴| 新油菜电影在线观看| 高清禁忌女孩:重置| 我是刑警策驰影院| 日本战狼8免费播放视频大全 | 电影《时间停止器》完整版在线观看 | 为全人类 第五季| 《私人女性监狱》hd免费高清在线观看 | xl司令免费高清全集| 春去春又回片尾曲| 理论免费| 《法国空乘8》观看| 《秘密》电影全集| 《人脉王》| 高清《老医馆》全集免费| 四川孃孃51岁拿下电竞冠军| 刚结婚和部长一起去出差旅| 爱情公寓第2季| 王屋下的传说| 《女版黑鹰坠落》H版| 明日战记在线观看免费完整版中文| 姐姐的好大| 暴躁老妈高清全集免费看| 异世界献身第1季动漫观看| 风水之王:改运第一人全集免费| 湿润的继拇HD中文| 《我的罪恶人生》| 青青珊瑚岛| 养生馆男在线观看完整版电影| 《赘婿》| 少年歌行萧瑟| fate天之杯3春之歌| 欢天喜地七仙女2| 荷尔蒙6在线观看免费版第三季| 且试天下电视剧全集| 还珠格格1| 需要爸爸播种籽2| 高清《钟表馆事件》电视剧| 冬日行动电影免费观看| 暴躁老妈高清全集免费看| 无人区电影完整版| 韩剧女人心| 女超人法国满天星完整版| 那金花和她的女婿46| 火影剧场版7| 姊妹牙医在线观看| 沧元图55| 生死线在线观看| 《安吉拉怀特》大尺度在线观看| 伊甸园之东国语版| 小丑回魂 电影| 法国私人航空无删减版| 痴汉地狱| 刀客家族女人全集| 电影我要爸爸的种子HD正版 | 熟妇和巨乳继拇做爰电影院| 她的初恋| 暗区突围秘密任务| 两个母亲ID两个妈妈| 湄公河大案28集| 白色月光电视剧免费观看| 《重返狼群》免费观看| 北京地震最新消息1分钟前| 黑白配高清国语版大全| 银魂256| 银河奥特曼免费观看全集| 巴黎恋歌| 天海翼护士在线| 大地资源在线观看免费高清电视| 陈小春电影全集国语| 男人和女人在一起愁愁愁电视剧免| 成人糗百| 王刚夜幕下的哈尔滨| 马拉松sr| 周弘打真军电影| 苏炳添说对不起大家| 同事三分亲粤语| 村枝普通话版| 快乐方程式 level c| 无上神帝全集免费观看| 《和讨厌的部长出差旅》电影在线观看| 龙门客栈在线观看免费完整版| 大女人小男人全集32| 布鲁克读大学1984完整版| 你的名字重映2024| 乾隆大帝粤语| 伦理电影法国护士长| 延禧宫略在线观看免费| 电影 保镖| 《播种女儿》完整版在线看| 极恶非道 1| 浪漫医生金师傅2| 建党伟业海报| 幸得相遇离婚时免费播放| 坎贝奇无憾1080P免费看| 永不磨灭的番号33| 《高潮》未删减| 替夫还债3高清完整版在线观看| 婚巢电视剧在线观看| 极品神医来打工| 战狼6免费观看西瓜视频| 聊斋艳谭幽| 迷离档案粤语| 19岁大学生免费观看视频| 哈哈哈哈哈第二季免费观看完整版| 我的猎物意大利| 小蜜桃15| 幸福一家人瓜| 厦门回应要求旅客抓紧离厦 | 长相思第60集完整版免费下载| 非常勿扰| 三年大片大全国语免费观| oh透明人间| 电影特种部队1| 法国空乘5免费高清原声满天星| 心宅猎人电视剧在线观看| 九九龟一| 渔夫的荒野史记在线播放| 鲜花朵朵免费观看完整版| 千日的约定| 弹幕记忆| 粉红大白菜在线免费观看| 切糕段子| 在菲被绑架中国人遗体疑发现 | 大男当婚全集免费观看| 塔尔萨之王免费观看| 单身老女人免费播放电视剧大全| 战狼6欧式少女全集资源百度云| 艰难爱情全集| 兵心依旧| 日本电影乳房按摩在线看| 电影共助2在线观看高清免费| 《疯狂动物城2》普通话免费观看| 甜美姐姐动漫全集| 唐探1900电影在线观看| 新建文件夹2线观看| 西部通缉令180分钟| 金瓶梅 单立文| 电影远山的呼唤| 出逃的公主| 电影需要爸爸播种子免费完整版在线观看| 半熟恋人综艺第三期下在线观看| 少林龙小子| 战狼15大学生免费看全集| 激战高清下载| 案发现场第二部全集| 木子凛子电影免费观看| 斗罗大陆在线| 男子吃月饼咬到螺丝磕坏2颗牙| 售楼部小姐的秘密在线观看| 梁朝伟绝代双骄| 甄嬛传第74集| yeyllow视频免费| 无人区1在线观看| 侏罗纪世界百度云盘| 隐行帽子免费完整版| 蛮荒种田全集免费| 年少轻狂| 电影《爱我几何》莫妮卡在线观看| 孤儿 电影| 黄金时代电影| 龙族第二季动漫免费看| 楚留香之采花大盗| 农场主三个女儿美国经典电影| 味道食在乡| 战狼6免费下载全集| 非诚勿扰20120331| 云裳广场舞爱情果| 妙警贼探完整版免费观看| 火影小王CC| 火烧云全集| 听说 彭于晏| 99re在线观看视频| 一不小心爱上你歌曲| 光环电影完整版在线看高清| 《卢旺达的玫瑰》完整版| 七夜雪电视剧全集免费播放| 米奇电影| 英雄本色2电影| 《入室暴行3被蹂躏》在线| 火蓝刀锋2| 娜塔莎 劳佳姆| 电影《需要爸爸播种子》HD中字在线观看,高清完整版美国倫理片_屠夫电影网 | 唐朝浪漫英雄下载| 海上孟府全集46集免费观看完整版| 啄木鸟女管家法国满天星电视剧| 肇事追踪演员表| 陆真传奇全集| 钢铿锵锵锵锵在线观看| 斗罗大陆第228集| 够劲吻住你短剧大结局免费观看| 高清我独自蜜月未删减| 八戒八戒网剧在线观看15| 阴阳眼见子未删减| 小峰娱乐网| 麻豆AV《修车艳遇》在线观看| 双子公主第一部| 洛克王国动画片| 暴走三金| 危险小胰子| 棋魂第2部| 火域凤凰| 《被下药强辱的妻子》电影| 《裙子下有野兽》| 因法之名免费全集在线观看| 美国队长3迅雷| 美国版本女儿国电影| 领袖电视剧| 电视剧咱们结婚吧全集| 酒店1-40集在线观看| 出包王女| 大头儿子小头爸爸2全集| 韩剧大度电影在线看| 儿媳妇的味道l| 复仇者联盟4在线| 山野女人香| 流落荒岛的兄妹电影在线观看免费| 棘手狂情电影| 台版《烈火女警花》| 课外授业3在线| 美姊妹牙医在线完整播放电影| 密爱电影| 关于我们之间的事| 第11个妈妈| 台湾黛比| 异装癖的女人| 金瓶梅在线高清观看无删减| 定制伴郎| 《卖保险的女销售》电影免费观看| 黑寡妇在线观看免费播放电影| 和朋友换娶妻野外夫妇3| 少年莫扎特| 长乐曲在线观看| 《交易》凯登克罗斯美国| 爷们儿电视剧大结局| 文成公主王庆爽| 双世宠妃第一季| 激战丛林电影在线观看| 生存之民工电视剧| 正者无敌演员| 陈柏宇电影| 销售的销售秘密6| 渴望hd| 四月一日灵异事件簿·继动漫| 毒刺入喉电影完整版在线看免费| 想要爸爸播种完整版| 电视剧赏金猎人| 24小时末路重生在线观看完整版| 菲律宾电影《健身房教练》的导演是 | 玄女心经免费观看完整版高清| 绝密卧底电视剧免费观看| 苦尽来遇见你韩剧免费观看全集| 酒店1一5集在线观看免费| 电视剧归路免费观看全集高清版| 喜爱夜蒲快播观看| 隔壁邻居很美味电视剧演员表| 《法国空乘5》无删减版 | 别动我手机| 古墓丽影法国满天星法版免费观看| 《叔叔》完整版| 亲爱的设计师电视剧免费观看| 朋友别哭刘芳| 性解秘| 《豆豆笑笑》未删减| 原始人电影免费完整版观看| 金蝉脱壳高清完整版| 总统之夜电影在线观看| 月夜闪灵| 大江大河第二部全集免费观看| 上海一家人电视剧全集在线观看| 伊比利亚三部曲在线观看| 迷人的新娘| 电视剧海天之恋| 贤妻良母完整版| ⅹl上司第1季末增减类型| 黄渤不醉mv| 门事件电影直播| 千机变3| 姜恩惠《特殊诊所》完整版| 千金驾到全集免费| 许我耀眼32集免费观看| 《误杀3》电影超清免费观看| 战狼6高清免费观看全集下载电影| 新福尔摩斯 第二季| 高清《大学》电影| 张康贾旭明为什么消失了| 美国需要爸爸播种电影| 电锯惊魂10在线观看| 监狱风云之少年犯| 后营露营无增减第二季预告| 日本美女|