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

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>
            尤物在线观看一区| 在线性视频日韩欧美| 国产主播一区| 亚洲免费在线观看| 亚洲欧洲日韩综合二区| 欧美一级久久久久久久大片| 国产精品盗摄久久久| 91久久香蕉国产日韩欧美9色| 久久激情婷婷| 亚洲男人的天堂在线观看| 国产精品扒开腿做爽爽爽视频| 夜夜嗨av一区二区三区| 亚洲国产精品尤物yw在线观看 | 亚洲第一精品夜夜躁人人躁| 久久成人资源| 国产一区视频网站| 久久中文在线| 免费欧美电影| 99精品欧美一区| 亚洲色无码播放| 国产精品有限公司| 久久久国产亚洲精品| 久久免费国产精品| 亚洲人成小说网站色在线| 亚洲国产一区二区a毛片| 欧美日韩免费高清| 欧美一区二区三区婷婷月色 | 亚洲盗摄视频| 亚洲丰满少妇videoshd| 欧美国产视频日韩| 在线性视频日韩欧美| 亚洲一区二区三区中文字幕| 国产午夜精品全部视频在线播放| 久久综合一区| 欧美激情视频网站| 亚洲免费在线精品一区| 欧美一区三区三区高中清蜜桃 | 亚洲精品一区二区在线| 亚洲精品乱码久久久久久久久 | 欧美一区二区三区婷婷月色| 欧美成人激情视频免费观看| 欧美福利小视频| 亚洲午夜久久久久久久久电影院 | 亚洲午夜视频在线观看| 亚洲欧美国产77777| 亚洲国产精品va在线看黑人动漫| 亚洲三级影片| 国内成人精品视频| 亚洲六月丁香色婷婷综合久久| 香港久久久电影| 亚洲精品久久久久久一区二区| aⅴ色国产欧美| 狠狠狠色丁香婷婷综合久久五月| 亚洲成色777777女色窝| 欧美调教视频| 欧美成年人在线观看| 国产精品久久999| 欧美黄色日本| 国产一区二区电影在线观看| 91久久在线| 激情欧美一区二区| 99国产精品国产精品久久| 国产有码一区二区| 一区二区三区四区五区精品视频| 在线观看日韩av先锋影音电影院 | 国产亚洲精品自拍| 亚洲美女中出| 亚洲国产福利在线| 午夜在线精品偷拍| 亚洲欧美日韩中文视频| 欧美精品一区二区精品网| 久久网站免费| 国产亚洲毛片在线| 亚洲欧美视频在线观看视频| 中文在线资源观看网站视频免费不卡 | 欧美成人免费观看| 国产色综合天天综合网| 亚洲少妇自拍| 亚洲婷婷综合色高清在线| 亚洲午夜高清视频| 欧美精品三级日韩久久| 欧美福利视频在线观看| 国内精品久久久久影院薰衣草| 亚洲一区二区三区视频| 亚洲调教视频在线观看| 欧美美女操人视频| 亚洲国产精品激情在线观看| 亚洲高清一二三区| 久久久久久久久久久久久女国产乱 | 久久成人国产| 国产精品毛片a∨一区二区三区|国 | 亚洲人成艺术| 欧美电影在线观看完整版| 欧美黑人一区二区三区| 在线色欧美三级视频| 久久精品日韩| 免费国产自线拍一欧美视频| 在线成人www免费观看视频| 久久精品亚洲精品| 免费久久99精品国产自在现线| 在线观看福利一区| 欧美承认网站| 一区二区三区四区国产精品| 欧美一区二区三区视频在线| 国产亚洲一区二区在线观看| 久久国产手机看片| 欧美激情视频一区二区三区免费| 亚洲九九爱视频| 国产精品久久久久久久久久尿 | 国产三区二区一区久久| 久久久夜精品| 亚洲三级视频| 久久av一区二区三区漫画| 影音先锋日韩精品| 欧美精品v日韩精品v韩国精品v| av不卡在线看| 久久久久国产精品一区三寸| 亚洲国产片色| 国产精品电影观看| 久久成人精品视频| 欧美激情在线免费观看| 亚洲欧美日韩中文视频| 伊人成人网在线看| 欧美色另类天堂2015| 久久成人免费| 日韩小视频在线观看专区| 性亚洲最疯狂xxxx高清| 亚洲高清不卡av| 国产精品成人午夜| 久久人人97超碰国产公开结果| 亚洲精品乱码久久久久| 久久九九精品| 亚洲性线免费观看视频成熟| 狠狠色狠狠色综合| 欧美午夜视频在线观看| 理论片一区二区在线| 亚洲自拍偷拍一区| 亚洲欧洲免费视频| 日韩一区二区电影网| 一区二区三区精品在线| 久久中文字幕一区二区三区| 一区二区三区日韩精品视频| 国产丝袜一区二区| 欧美日韩在线播| 美女国产一区| 欧美在线视频免费播放| 亚洲天堂男人| 亚洲精品欧洲| 欧美激情a∨在线视频播放| 久久黄色级2电影| 午夜国产不卡在线观看视频| 亚洲乱码精品一二三四区日韩在线| 国产婷婷成人久久av免费高清| 欧美日韩在线免费| 欧美成人免费在线观看| 久久精品人人做人人爽电影蜜月| 亚洲制服av| 亚洲深夜av| 在线亚洲美日韩| 亚洲精品亚洲人成人网| 亚洲高清视频一区二区| 欧美ed2k| 欧美gay视频激情| 久久综合影音| 麻豆成人精品| 噜噜噜躁狠狠躁狠狠精品视频| 欧美在线网址| 久久国产日韩欧美| 欧美资源在线观看| 欧美综合二区| 久久久综合精品| 久久免费99精品久久久久久| 久久国产加勒比精品无码| 性做久久久久久| 欧美在线视频播放| 久久久久久夜精品精品免费| 久久久精品国产一区二区三区| 久久精品论坛| 乱人伦精品视频在线观看| 噜噜噜噜噜久久久久久91| 免费在线欧美视频| 亚洲福利一区| 日韩午夜中文字幕| 亚洲一区亚洲| 欧美一级欧美一级在线播放| 欧美一区二区三区视频| 久久久国际精品| 麻豆久久精品| 欧美日韩在线观看一区二区| 国产精品任我爽爆在线播放| 国产日韩欧美自拍| 精品成人在线观看| 亚洲精品欧洲| 亚洲欧美日韩精品久久久久 | 久久综合久久综合久久| 欧美jjzz| 国产精品欧美日韩久久| 国产一区免费视频| 最近中文字幕日韩精品 | 久久久精品国产99久久精品芒果|