青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

longshanks

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  14 Posts :: 0 Stories :: 214 Comments :: 0 Trackbacks

常用鏈接

留言簿(10)

我參與的團隊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

C++的營養

莫華楓
    動物都會攝取食物,吸收其中的營養,用于自身生長和活動。然而,并非食物中所有的物質都能為動物所吸收。那些無法消化的物質,通過消化道的另一頭(某些動 物消化道只有一頭)排出體外。不過,一種動物無法消化的排泄物,是另一種動物(生物)的食物,后者可以從中攝取所需的營養。
    一門編程語言,對于程序員而言,如同食物那樣,包含著所需的養分。當然也包含著無法消化的東西。不同的是,隨著程序員不斷成長,會逐步消化過去無法消化的那些東西。
    C++可以看作一種成分復雜的食物,對于多數程序員而言,是無法完全消化的。正因為如此,很多程序員認為C++太難以消化,不應該去吃它。但是,C++的 營養不可謂不豐富,就此舍棄,而不加利用,則是莫大的罪過。好在食物可以通過加工,變得易于吸收,比如說發酵。鑒于程序員們的消化能力的差異,也為了讓C ++的營養能夠造福他人,我就暫且扮演一回酵母菌,把C++的某些營養單獨提取出來,并加以分解,讓那些消化能力不太強的程序員也能享受它的美味。:)
    (為了讓這些營養便于消化,我將會用C#做一些案例。選擇C#的原因很簡單,因為我熟悉。:))

RAII

    RAII,好古怪的營養啊!它的全稱應該是“Resource Acquire Is Initial”。這是C++創始人Bjarne Stroustrup發明的詞匯,比較令人費解。說起來,RAII的含義倒也不算復雜。用白話說就是:在類的構造函數中分配資源,在析構函數中釋放資源。 這樣,當一個對象創建的時候,構造函數會自動地被調用;而當這個對象被釋放的時候,析構函數也會被自動調用。于是乎,一個對象的生命期結束后將會不再占用 資源,資源的使用是安全可靠的。
    下面便是在C++中實現RAII的典型代碼:
        class file
        {
        
public:
            file(
string const& name) {
                   m_fileHandle
=open_file(name.cstr());
            }
            
~file() {
                   close_file(m_fileHandle);
            }
            ...
        
private:
            handle m_fileHandle;
        }
    很典型的“在構造函數里獲取,在析構函數里釋放”。如果我寫下代碼:       
        void fun1() {
            file myfile(
"my.txt");
            ... 
//操作文件
        }
    //此處銷毀對象,調用析構函數,釋放資源
    當函數結束時,局部對象myfile的生命周期也結束了,析構函數便會被調用,資源會得到釋放。而且,如果函數中的代碼拋出異常,那么析構函數也會被調用,資源同樣會得到釋放。所以,在RAII下,不僅僅資源安全,也是異常安全的。
    但是,在如下的代碼中,資源不是安全的,盡管我們實現了RAII:
         void fun2() {
             file pfile
=new file("my.txt");
                ... 
//操作文件
         }
    因為我們在堆上創建了一個對象(通過new),但是卻沒有釋放它。我們必須運用delete操作符顯式地加以釋放:
        void fun3() {
             file pfile
=new file("my.txt");
                ... 
//操作文件
                delete pfile;
        }
    否則,非但對象中的資源得不到釋放,連對象本身的內存也得不到回收。(將來,C++的標準中將會引入GC(垃圾收集),但正如下面分析的那樣,GC依然無法確保資源的安全)。
    現在,在fun3(),資源是安全的,但卻不是異常安全的。因為一旦函數中拋出異常,那么delete pfile;這句代碼將沒有機會被執行。C++領域的諸位大牛們告誡我們:如果想要在沒有GC的情況下確保資源安全和異常安全,那么請使用智能指針:
        void fun4() {
              shared_ptr
<file> spfile(new file("my.txt"));
              ... 
//操作文件
        }
  //此處,spfile結束生命周期的時候,會釋放(delete)對象
    那么,智能指針又是怎么做到的呢?下面的代碼告訴你其中的把戲(關于智能指針的更進一步的內容,請參考std::auto_ptr,boost或tr1的智能指針):
        template<typename T>
        
class smart_ptr
        
{
        
public:
            smart_ptr(T
* p):m_ptr(p) {}
            
~smart_ptr() { delete m_ptr; }
            ...
        
private:
            T
* m_ptr;
        }
    沒錯,還是RAII。也就是說,智能指針通過RAII來確保內存資源的安全,也間接地使得對象上的RAII得到實施。不過,這里的RAII并不是十分嚴 格:對象(所占的內存也是資源)的創建(資源獲取)是在構造函數之外進行的。廣義上,我們也把它劃歸RAII范疇。但是,Matthew Wilson在《Imperfect C++》一書中,將其獨立出來,稱其為RRID(Resource Release Is Destruction)。RRID的實施需要在類的開發者和使用者之間建立契約,采用相同的方法獲取和釋放資源。比如,如果在shared_ptr構造 時使用malloc(),便會出現問題,因為shared_ptr是通過delete釋放對象的。
    對于內置了GC的語言,資源管理相對簡單。不過,事情并非總是這樣。下面的C#代碼摘自MSDN Library的C#編程指南,我略微改造了一下:
        static void CodeWithoutCleanup()
        
{
            System.IO.FileStream file 
= null;
            System.IO.FileInfo fileInfo 
= new System.IO.FileInfo("C:\file.txt");
            file 
= fileInfo.OpenWrite();
            file.WriteByte(
0xF);
        }
    那么資源會不會泄漏呢?這取決于對象的實現。如果通過OpenWrite()獲得的FileStream對象,在析構函數中執行了文件的釋放操作,那么資 源最終不會泄露。因為GC最終在執行GC操作的時候,會調用Finalize()函數(C#類的析構函數會隱式地轉換成Finalize()函數的重 載)。這是由于C#使用了引用語義(嚴格地講,是對引用類型使用引用語義),一個對象實際上不是對象本身,而是對象的引用。如同C++中的那樣,引用在離 開作用域時,是不會釋放對象的。否則,便無法將一個對象直接傳遞到函數之外。在這種情況下,如果沒有顯式地調用Close()之類的操作,資源將不會得到 立刻釋放。但是像文件、鎖、數據庫鏈接之類屬于重要或稀缺的資源,如果等到GC執行回收,會造成資源不足。更有甚者,會造成代碼執行上的問題。我曾經遇到 過這樣一件事:我執行了一個sql操作,獲得一個結果集,然后執行下一個sql,結果無法執行。這是因為我使用的SQL Server 2000不允許在一個數據連接上同時打開兩個結果集(很多數據庫引擎都是這樣)。第一個結果集用完后沒有立刻釋放,而GC操作則尚未啟動,于是便造成在一 個未關閉結果集的數據連接上無法執行新的sql的問題。
    所以,只要涉及了內存以外的資源,應當盡快釋放。(當然,如果內存能夠盡快釋放,就更好了)。對于上述CodeWithoutCleanup()函數,應當在最后調用file對象上的Close()函數,以便釋放文件:
        static void CodeWithoutCleanup()
        
{
            System.IO.FileStream file 
= null;
            System.IO.FileInfo fileInfo 
= new System.IO.FileInfo("C:\file.txt");
            file 
= fileInfo.OpenWrite();
            file.WriteByte(
0xF);
            file.Close();
        }
    現在,這個函數是嚴格資源安全的,但卻不是嚴格異常安全的。如果在文件的操作中拋出異常,Close()成員將得不到調用。此時,文件也將無法及時關閉,直到GC完成。為此,需要對異常作出處理:
        static void CodeWithCleanup()
        
{
            System.IO.FileStream file 
= null;
            System.IO.FileInfo fileInfo 
= null;
            
try
            
{
                fileInfo 
= new System.IO.FileInfo("C:\file.txt");
                file 
= fileInfo.OpenWrite();
                file.WriteByte(
0xF);
            }

            
catch(System.Exception e)
            
{
                System.Console.WriteLine(e.Message);
            }

            
finally
            
{
                
if (file != null)
                
{
                    file.Close();
                }

            }

       }
    try-catch-finally是處理這種情況的標準語句。但是,相比前面的C++代碼fun1()和fun4()繁瑣很多。這都是沒有RAII的后果啊。下面,我們就來看看,如何在C#整出RAII來。
    一個有效的RAII應當包含兩個部分:構造/析構函數的資源獲取/釋放和確定性的析構函數調用。前者在C#中不成問題,C#有構造函數和析構函數。不過, C#的構造函數和析構函數是不能用于RAII的,原因一會兒會看到。正確的做法是讓一個類實現IDisposable接口,在IDisposable:: Dispose()函數中釋放資源:
        class RAIIFile : IDisposable
        
{
        
public RAIIFile(string fn) {
                System.IO.FileInfo fileInfo 
= new System.IO.FileInfo(fn);
                file 
= fileInfo.OpenWrite();
            }


        
public void Dispose() {
                  file.Close();
              }


        
private System.IO.FileStream file = null;
        }
    下一步,需要確保文件在退出作用域,或發生異常時被確定性地釋放。這項工作需要通過C#的using語句實現:
        static void CodeWithRAII()
        
{
            
using(RAIIFile file=new RAIIFile("C:\file.txt"))
            
{
                ... 
//操作文件
            }
 //文件釋放
        }
    一旦離開using的作用域,file.Dispose()將被調用,文件便會得到釋放,即便拋出異常,亦是如此。相比CodeWithCleanup ()中那坨雜亂繁復的代碼,CodeWithRAII()簡直可以算作賞心悅目。更重要的是,代碼的簡潔和規則將會大幅減少出錯可能性。值得注意的是 using語句只能作用于實現IDisposable接口的類,即便實現了析構函數也不行。所以對于需要得到RAII的類,必須實現 IDisposable。通常,凡是涉及到資源的類,都應該實現這個接口,便于日后使用。實際上,.net庫中的很多與非內存資源有關的類,都實現了 IDisposable,都可以利用using直接實現RAII。
    但是,還有一個問題是using無法解決的,就是如何維持類的成員函數的RAII。我們希望一個類的成員對象在該類實例創建的時候獲取資源,而在其銷毀的時候釋放資源:
        class X
        
{
        
public:
            X():m_file(
"c:\file.txt"{}
        
private:
            File m_file;    
//在X的實例析構時調用File::~File(),釋放資源。
        }
    但是在C#中無法實現。由于uing中實例化的對象在離開using域的時候便釋放了,無法在構造函數中使用:
        class X
        
{
            
public X() {
                
using(m_file=new RAIIFile("C:\file.txt"))
                
{
                }
//此處m_file便釋放了,此后m_file便指向無效資源
            }

            pravite RAIIFile m_file;
        }
    對于成員對象的RAII只能通過在析構函數或Dispose()中手工地釋放。我還沒有想出更好的辦法來。
    至此,RAII的來龍去脈已經說清楚了,在C#里也能從中汲取到充足的養分。但是,這還不是RAII的全部營養,RAII還有更多的擴展用途。在 《Imperfect C++》一書中,Matthew Wilson展示了RAII的一種非常重要的應用。為了不落個鸚鵡學舌的名聲,這里我給出一個真實遇到的案例,非常簡單:我寫的程序需要響應一個Grid 控件的CellTextChange事件,執行一些運算。在響應這個事件(執行運算)的過程中,不能再響應同一個事件,直到處理結束。為此,我設置了一個 標志,用來控制事件響應:
        class MyForm
        
{
        
public:
            MyForm():is_cacul(
false{}
            ...
            
void OnCellTextChange(Cell& cell) {
                
if(is_cacul)
                    
return;
                is_cacul
=true;
                ... 
//執行計算任務
                is_cacul=false;
            }

        
private:
            
bool is_cacul;
        }
;
    但是,這里的代碼不是異常安全的。如果在執行計算的過程中拋出異常,那么is_cacul標志將永遠是true。此后,即便是正常的 CellTextChange也無法得到正確地響應。同前面遇到的資源問題一樣,傳統上我們不得不求助于try-catch語句。但是如果我們運用 RAII,則可以使得代碼簡化到不能簡化,安全到不能再安全。我首先做了一個類:
        class BoolScope
        
{
        
public:
            BoolScope(
bool& val, bool newVal)
                :m_val(val), m_old(val) 
{
                m_val
=newVal;
            }

            
~BoolScope() {
                m_val
=m_old;
            }


        
private:
            
bool& m_val;
            
bool m_old;
        }
;
    這個類的作用是所謂“域守衛(scoping)”,構造函數接受兩個參數:第一個是一個bool對象的引用,在構造函數中保存在m_val成員里;第二個 是新的值,將被賦予傳入的那個bool對象。而該對象的原有值,則保存在m_old成員中。析構函數則將m_old的值返還給m_val,也就是那個 bool對象。有了這個類之后,便可以很優雅地獲得異常安全:
        class MyForm
        
{
        
public:
            MyForm():is_cacul(
false{}
            ...
            
void OnCellTextChange(Cell& cell) {
                
if(is_cacul)
                    
return;
                BoolScope bs_(is_cacul, 
true);
                ... 
//執行計算任務
            }

        
private:
            
bool is_cacul;
        }
;
    好啦,任務完成。在bs_創建的時候,is_cacul的值被替換成true,它的舊值保存在bs_對象中。當OnCellTextChange()返回 時,bs_對象會被自動析構,析構函數會自動把保存起來的原值重新賦給is_cacul。一切又都回到原先的樣子。同樣,如果異常拋出,is_cacul 的值也會得到恢復。
    這個BoolScope可以在將來繼續使用,分攤下來的開發成本幾乎是0。更進一步,可以開發一個通用的Scope模板,用于所有類型,就像《Imperfect C++》里的那樣。
    下面,讓我們把戰場轉移到C#,看看C#是如何實現域守衛的。考慮到C#(.net)的對象模型的特點,我們先實現引用類型的域守衛,然后再來看看如何對付值類型。其原因,一會兒會看到。
    我曾經需要向一個grid中填入數據,但是填入的過程中,控件不斷的刷新,造成閃爍,也影響性能,除非把控件上的AutoDraw屬性設為false。為此,我做了一個域守衛類,在填寫操作之前關上AutoDraw,完成或異常拋出時再打開:
        class DrawScope : IDisposable
        
{
            
public DrawScope(Grid g, bool val) {
                m_grid
=g;
                m_old
=g->AutoDraw;
                m_grid
->AutoDraw=val;
            }

            
public void Dispose() {
                    g
->AutoDraw=m_old;
               }

            
private Grid m_grid;
            
private bool m_old;
        }
;
    于是,我便可以如下優雅地處理AutoDraw屬性設置問題:
        static void LoadData(Grid g) {
            
using(DrawScope ds=new DrawScope(g, false))
            
{
                ... 
//執行數據裝載
            }

        }
    現在,我們回過頭,來實現值類型的域守衛。案例還是采用前面的CellTextChange事件。當我試圖著手對那個is_cacul執行域守衛時,遇到了不小的麻煩。起初,我寫下了這樣的代碼:
        class BoolScope
        
{
            
private ??? m_val; //此處用什么類型?
            private bool m_old;
        }
;
    m_val應當是一個指向一個對象的引用,C#是沒有C++那些指針和引用的。在C#中,引用類型定義的對象實際上是一個指向對象的引用;而值類型定義的 對象實際上是一個對象,或者說“棧對象”,但卻沒有一種指向值類型的引用。(關于這種對象模型的優劣,后面的“題外話”小節有一些探討)。我嘗試著采用兩 種辦法,一種不成功,而另一種成功了。
    C#(.net)有一種box機制,可以將一個值對象打包,放到堆中創建。這樣,或許可以把一個值對象編程引用對象,構成C#可以引用的東西:
        class BoolScope : IDisposable
        
{
            
public BoolScope(object val, bool newVal) {
                    m_val
=val;                 //#1
                    m_old=(bool)val;
                    (
bool)m_val=newVal;    //#2
            }

            
public void Dispose() {
                    (
bool)m_val=m_old;    //#3
               }

            
private object m_val;
            
private bool m_old;
        }
    使用時,應當采用如下形式:
        class MyForm
        
{
            
public MyForm() {
                is_cacul
=new bool(false); //boxing
            }

            ...
            
void OnCellTextChange(Cell& cell) {
                
if(is_cacul)
                    
return;
                
using(BoolScope bs=new BoolScope(is_cacul, true))
                
{
                    ... 
//執行計算任務
                }

            }

            
private object is_cacul;
        }
;
    很可惜,此路不通。因為在代碼#1的地方,并未執行引用語義,而執行了值語義。也就是說,沒有把val(它是個引用)的值賦給m_val(也是個引用), 而是為m_val做了個副本。以至于在代碼#2和#3處無法將newVal和m_old賦予val(也就是is_cacul)。或許C#的設計者有無數理 由說明這種設計的合理性,但是在這里,卻扼殺了一個非常有用的idom。而且,缺少對值對象的引用手段,大大限制了語言的靈活性和擴展性。
    第二種方法就非常直白了,也絕對不應當出問題,就是使用包裝類:
        class BoolVal
        
{
            
public BoolVal(bool v)
            
{
                m_val
=v;
            }

            
public bool getVal() {
                
return m_val;
            }

            
public void setVal(bool v) {
                m_val
=v;
            }

            
private bool m_val;
        }

        
class BoolScope : IDisposable
        
{
            
public IntScope(BoolVal iv, bool v)
            
{
                m_old 
= iv.getVal();
                m_Val 
= iv;
                m_Val.setVal(v);
            }

            
public virtual void Dispose()
            
{
                m_Val.setVal(m_old);
            }

            
private BoolVal m_Val;
            
private bool m_old;
        }
    這里,我做了一個包裝類BoolVal,是個引用類。然后以此為基礎,編寫了一個BoolScope類。然后,便可以正常使用域守衛:
        class MyForm
        
{
            
public MyForm() {
                m_val.setVal(
false); //boxing
            }

            ...
            
void OnCellTextChange(Cell& cell) {
                
if(is_cacul)
                    
return;
                
using(BoolScope bs=new BoolScope(m_val, true))
                
{
                    ... 
//執行計算任務
                }

            }

            
private BoolVal m_val;
        }
;
    好了,一切都很不錯。盡管C#的對象模型給我們平添了不少麻煩,使得我多寫了不少代碼,但是使用域守衛類仍然是一本萬利的事情。作為GP fans,我當然也嘗試著在C#里做一些泛型,以免去反復開發包裝類和域守衛類的苦惱。這些東西,就留給大家做練習吧。:)
    在某些場合下,我們可能會對一些對象做一些操作,完事后在恢復這個對象的原始狀態,這也是域守衛類的用武之地。只是守衛一個結構復雜的類,不是一件輕松的 工作。最直接的做法是取出所有的成員數據,在結束后再重新復制回去。這當然是繁復的工作,而且效率不高。但是,我們將在下一篇看到,如果運用swap手 法,結合復制構造函數,可以很方便地實現這種域守衛。這我們以后再說。
    域守衛作為RAII的一個擴展應用,非常簡單,但卻極具實用性。如果我們對“資源”這個概念加以推廣,把一些值、狀態等等內容都納入資源的范疇,那么域守衛類的使用是順理成章的事。

題外話:C#的對象模型

    C#的設計理念是簡化語言的學習和使用。但是,就前面案例中出現的問題而言,在特定的情況下,特別是需要靈活和擴展的時候,C#往往表現的差強人意。C# 的對象模型實際上是以堆對象和引用語義為核心的。不過,考慮到維持堆對象的巨大開銷和性能損失,應用在一些簡單的類型上,比如int、float等等,實 在得不嘗失。為此,C#將這些簡單類型直接作為值處理,當然也允許用戶定義自己的值類型。值類型擁有值語義。而值類型的本質是棧對象,引用類型則是堆對 象。
    這樣看起來應該是個不錯的折中,但是實際上卻造成了不大不小的麻煩。前面的案例已經明確地表現了這種對象模型引發的麻煩。由于C#拋棄值和引用的差異(為 了簡化語言的學習和使用),那么對于一個引用對象,我們無法用值語義訪問它;而對于一個值對象,我們無法用引用語義訪問。對于前者,不會引發本質性的問 題,因為我們可以使用成員函數來實現值語義。但是對于后者,則是無法逾越的障礙,就像在BoolScope案例中表現的那樣。在這種情況下,我們不得不用 引用類包裝值類型,使得值類型喪失了原有的性能和資源優勢。
    更有甚者,C#的對象模型有時會造成語義上的沖突。由于值類型使用值語義,而引用類型使用引用語義。那么同樣是對象定義,便有可能使用不同的語義:
        int i, j=10;  //值類型
        i=j;            //值語義,兩個對象復制內容
        i=5;           //i==5, j==10
        StringBuilder s1, s2 = new StringBuilder("s2");   //引用類型
        s1 = s2;        //引用語義,s1和s2指向同一個對象
        s1.Append(" is s1");    //s1==s2=="s1 is s2"
    同一個形式具有不同語義,往往會造成意想不到的問題。比如,在軟件開發的最初時刻,我們認為某個類型是值類型就足夠了,還可以獲得性能上的好處。但是,隨 著項目進入后期階段,發現最初的設計有問題,值類型限制了該類型的某些特性(如不能擁有析構函數,不能引用等等),那么需要把它改成引用類型。于是便引發 一大堆麻煩,需要檢查所有使用該類型的代碼,然后把賦值操作改成復制操作。這肯定不是討人喜歡的工作。為此,在實際開發中,很少自定義值類型,以免將來自縛手腳。于是,值類型除了語言內置類型和.net庫預定義的類型外,成了一件擺設。
    相比之下,傳統語言,如Ada、C、C++、Pascal等,區分引用和值的做法盡管需要初學者花更多的精力理解其中的差別,但在使用中則更加妥善和安全。畢竟學習是暫時的,使用則是永遠的。
posted on 2008-02-16 08:19 longshanks 閱讀(2076) 評論(2)  編輯 收藏 引用

Feedback

# re: C++的營養 2008-02-16 11:47 abettor
用對照的方法學習確實是一個很不錯的方法。  回復  更多評論
  

# re: C++的營養 2008-02-22 16:45 i
file pfile=new file("my.txt");
應該改為
file *pfile=new file("my.txt");  回復  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品无人区| 欧美3dxxxxhd| 国产精品中文在线| 亚洲性图久久| 亚洲日韩第九十九页| 久久五月激情| 亚洲国产精品成人综合色在线婷婷| 久久精品成人| 久久久久久久综合| 亚洲国产影院| 亚洲精品欧美日韩专区| 欧美亚韩一区| 欧美影院精品一区| 久久精品在这里| 亚洲电影网站| 日韩午夜免费视频| 国产精品视频在线观看| 久久久999国产| 美女图片一区二区| 一区二区三区毛片| 亚洲女性裸体视频| 亚洲第一精品夜夜躁人人爽| 亚洲国产精品女人久久久| 欧美日韩成人综合| 久久精品99国产精品日本| 久久亚洲精品一区二区| 99国内精品久久| 亚洲欧美激情诱惑| 亚洲国产美国国产综合一区二区 | 老司机精品导航| 亚洲二区三区四区| 夜夜夜久久久| 亚洲第一在线综合在线| 日韩亚洲欧美一区二区三区| 国产乱码精品一区二区三| 欧美第一黄网免费网站| 欧美色欧美亚洲另类二区| 久久久之久亚州精品露出| 欧美刺激午夜性久久久久久久| 亚洲欧美日韩一区| 美女久久网站| 小嫩嫩精品导航| 欧美aa在线视频| 欧美一区二区三区四区在线观看| 久久夜色精品| 香蕉成人久久| 欧美精品激情在线| 葵司免费一区二区三区四区五区| 欧美欧美午夜aⅴ在线观看| 久久九九国产精品| 欧美日韩一视频区二区| 欧美成人综合一区| 亚洲午夜电影| 日韩视频在线一区二区| 久久久久久久久伊人| 欧美一区二区大片| 欧美日本三区| 亚洲激情视频在线| 在线看片成人| 久久成人免费视频| 亚洲欧美日韩综合国产aⅴ| 欧美大片免费观看| 欧美大色视频| 狠狠入ady亚洲精品| 午夜精品久久久久久久久久久久久 | 国产精品美女在线| 亚洲日本精品国产第一区| 亚洲国产精品久久久久婷婷884 | 在线成人国产| 香蕉免费一区二区三区在线观看| 亚洲一区二区三区高清| 欧美成人亚洲成人| 亚洲黄色成人网| 亚洲精品国精品久久99热| 女女同性精品视频| 亚洲第一中文字幕| 亚洲全部视频| 欧美日韩精品高清| 99精品视频网| 午夜精品一区二区三区在线视 | 午夜欧美大尺度福利影院在线看| 欧美日韩dvd在线观看| 亚洲精品中文字幕在线| 一道本一区二区| 欧美三级韩国三级日本三斤| av不卡在线观看| 亚洲综合999| 国产啪精品视频| 久久久7777| 欧美激情在线狂野欧美精品| 亚洲乱码国产乱码精品精98午夜 | 女女同性女同一区二区三区91| 国产在线精品二区| 另类激情亚洲| 亚洲精品一区久久久久久| 亚洲在线播放| 国产一区二区三区在线播放免费观看| 欧美一区观看| 亚洲高清不卡一区| 亚洲男人的天堂在线观看| 国产一区99| 欧美搞黄网站| 亚洲中字在线| 欧美国产一区二区在线观看| 这里只有精品视频| 国产手机视频一区二区| 欧美成人免费在线观看| 亚洲午夜精品久久| 女同性一区二区三区人了人一 | 欧美精品97| 亚洲婷婷免费| 欧美成人免费一级人片100| 国产麻豆日韩欧美久久| 美女网站久久| 亚洲一二三区视频在线观看| 欧美va天堂| 亚洲欧美中文另类| 在线看日韩欧美| 国产精品久久久久久av下载红粉 | 在线观看一区二区视频| 欧美成人资源| 欧美怡红院视频| 一区二区三区久久精品| 欧美11—12娇小xxxx| 亚洲欧美制服中文字幕| 亚洲激情视频在线播放| 国产日韩一区| 欧美深夜福利| 欧美jizzhd精品欧美喷水| 亚洲欧美精品一区| 亚洲伦理网站| 欧美激情一区二区三区蜜桃视频 | 欧美国产日韩视频| 午夜精品理论片| 一区二区三区高清在线 | 影音先锋亚洲视频| 国产精品国产成人国产三级| 欧美~级网站不卡| 久久久精彩视频| 欧美影院一区| 亚洲欧美一区二区精品久久久| 亚洲乱码日产精品bd| 亚洲黄色高清| 欧美激情视频一区二区三区在线播放| 久久国产精品72免费观看| 午夜免费在线观看精品视频| 亚洲一区二区久久| 亚洲视频在线观看| 一区二区成人精品| 亚洲免费电影在线观看| 亚洲精品乱码久久久久久黑人| 伊人色综合久久天天五月婷| 国产一区二区三区最好精华液| 国产农村妇女精品一区二区| 国产精品捆绑调教| 国产精品日本精品| 国产精品视频导航| 国产麻豆日韩欧美久久| 国产欧美一区二区三区另类精品 | 亚洲免费高清视频| 亚洲国产精品久久久久秋霞蜜臀| 亚洲国产成人精品久久久国产成人一区| 国产日韩综合| 精品999网站| 亚洲黄页视频免费观看| 亚洲看片免费| 亚洲欧美变态国产另类| 午夜老司机精品| 久久婷婷人人澡人人喊人人爽| 久久综合久久综合这里只有精品| 久久综合色88| 亚洲六月丁香色婷婷综合久久| 日韩视频在线一区二区| 亚洲夜间福利| 久久精品99无色码中文字幕 | 亚洲影院污污.| 亚洲综合视频在线| 亚洲欧洲综合另类在线| 亚洲少妇一区| 久久成人资源| 亚洲第一在线视频| 一区二区三区|亚洲午夜| 亚洲自拍电影| 葵司免费一区二区三区四区五区| 欧美激情一区二区三区在线视频| 国产精品草草| 伊人久久综合97精品| 一区二区动漫| 久久久综合网| 日韩亚洲国产欧美| 久久嫩草精品久久久久| 欧美三级视频在线| 韩日精品中文字幕| 这里只有精品在线播放| 久久久久久网| 亚洲午夜av在线| 欧美电影电视剧在线观看| 国产免费成人| 亚洲视频二区| 欧美高清在线播放|