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

陳碩的Blog

C++ 工程實(shí)踐(8):值語義

陳碩 (giantchen_AT_gmail)
http://blog.csdn.net/Solstice  http://weibo.com/giantchen
陳碩關(guān)于 C++ 工程實(shí)踐的系列文章: http://blog.csdn.net/Solstice/category/802325.aspx
排版正常的版本: http://www.cnblogs.com/Solstice/category/287661.html
陳碩博客文章合集下載: http://blog.csdn.net/Solstice/archive/2011/02/24/6206154.aspx
本作品采用“Creative Commons 署名-非商業(yè)性使用-禁止演繹 3.0 Unported 許可協(xié)議(cc by-nc-nd)”進(jìn)行許可。http://creativecommons.org/licenses/by-nc-nd/3.0/

本文是前一篇《C++ 工程實(shí)踐(7):iostream 的用途與局限》的后續(xù),在這篇文章的“iostream 與標(biāo)準(zhǔn)庫其他組件的交互”一節(jié),我簡(jiǎn)單地提到iostream的對(duì)象和C++標(biāo)準(zhǔn)庫中的其他對(duì)象(主要是容器和string)具有不同的語義,主要體現(xiàn)在iostream不能拷貝或賦值。今天全面談一談我對(duì)這個(gè)問題的理解。

本文的“對(duì)象”定義較為寬泛,a region of memory that has a type,在這個(gè)定義下,int、double、bool 變量都是對(duì)象。

什么是值語義

值語義(value sematics)指的是對(duì)象的拷貝與原對(duì)象無關(guān),就像拷貝 int 一樣。C++ 的內(nèi)置類型(bool/int/double/char)都是值語義,標(biāo)準(zhǔn)庫里的 complex<> 、pair<>、vector<>、map<>、string 等等類型也都是值語意,拷貝之后就與原對(duì)象脫離關(guān)系。Java 語言的 primitive types 也是值語義。

與值語義對(duì)應(yīng)的是“對(duì)象語義/object sematics”,或者叫做引用語義(reference sematics),由于“引用”一詞在 C++ 里有特殊含義,所以我在本文中使用“對(duì)象語義”這個(gè)術(shù)語。對(duì)象語義指的是面向?qū)ο笠饬x下的對(duì)象,對(duì)象拷貝是禁止的。例如 muduo 里的 Thread 是對(duì)象語義,拷貝 Thread 是無意義的,也是被禁止的:因?yàn)?Thread 代表線程,拷貝一個(gè) Thread 對(duì)象并不能讓系統(tǒng)增加一個(gè)一模一樣的線程。

同樣的道理,拷貝一個(gè) Employee 對(duì)象是沒有意義的,一個(gè)雇員不會(huì)變成兩個(gè)雇員,他也不會(huì)領(lǐng)兩份薪水。拷貝 TcpConnection 對(duì)象也沒有意義,系統(tǒng)里邊只有一個(gè) TCP 連接,拷貝 TcpConnection  對(duì)象不會(huì)讓我們擁有兩個(gè)連接。Printer 也是不能拷貝的,系統(tǒng)只連接了一個(gè)打印機(jī),拷貝 Printer 并不能憑空增加打印機(jī)。凡此總總,面向?qū)ο笠饬x下的“對(duì)象”是 non-copyable。

Java 里邊的 class 對(duì)象都是對(duì)象語義/引用語義。ArrayList<Integer> a = new ArrayList<Integer>(); ArrayList<Integer> b = a; 那么 a 和 b 指向的是同一個(gè)ArrayList 對(duì)象,修改 a 同時(shí)也會(huì)影響 b。

值語義與 immutable 無關(guān)。Java 有 value object 一說,按(PoEAA 486)的定義,它實(shí)際上是 immutable object,例如 String、Integer、BigInteger、joda.time.DateTime 等等(因?yàn)?Java 沒有辦法實(shí)現(xiàn)真正的值語義 class,只好用 immutable object 來模擬)。盡管 immutable object 有其自身的用處,但不是本文的主題。muduo 中的 Date、Timestamp 也都是 immutable 的。

C++中的值語義對(duì)象也可以是 mutable,比如 complex<>、pair<>、vector<>、map<>、string 都是可以修改的。muduo 的 InetAddress 和 Buffer 都具有值語義,它們都是可以修改的。

值語義的對(duì)象不一定是 POD,例如 string 就不是 POD,但它是值語義的。

值語義的對(duì)象不一定小,例如 vector<int> 的元素可多可少,但它始終是值語義的。當(dāng)然,很多值語義的對(duì)象都是小的,例如complex<>、muduo::Date、muduo::Timestamp。

值語義與生命期

值語義的一個(gè)巨大好處是生命期管理很簡(jiǎn)單,就跟 int 一樣——你不需要操心 int 的生命期。值語義的對(duì)象要么是 stack object,或者直接作為其他 object 的成員,因此我們不用擔(dān)心它的生命期(一個(gè)函數(shù)使用自己stack上的對(duì)象,一個(gè)成員函數(shù)使用自己的數(shù)據(jù)成員對(duì)象)。相反,對(duì)象語義的 object 由于不能拷貝,我們只能通過指針或引用來使用它。

一旦使用指針和引用來操作對(duì)象,那么就要擔(dān)心所指的對(duì)象是否已被釋放,這一度是 C++ 程序 bug 的一大來源。此外,由于 C++ 只能通過指針或引用來獲得多態(tài)性,那么在C++里從事基于繼承和多態(tài)的面向?qū)ο缶幊逃衅浔举|(zhì)的困難——資源管理。

考慮一個(gè)簡(jiǎn)單的對(duì)象建模——家長(zhǎng)與子女:a Parent has a Child, a Child knows his/her Parent。在 Java 里邊很好寫,不用擔(dān)心內(nèi)存泄漏,也不用擔(dān)心空懸指針:

public class Parent
{
    private Child myChild;
}
    
public class Child
{
    private Parent myParent;
}

只要正確初始化 myChild 和 myParent,那么 Java 程序員就不用擔(dān)心出現(xiàn)訪問錯(cuò)誤。一個(gè) handle 是否有效,只需要判斷其是否 non null。

在 C++ 里邊就要為資源管理費(fèi)一番腦筋:Parent 和 Child 都代表的是真人,肯定是不能拷貝的,因此具有對(duì)象語義。Parent 是直接持有 Child 嗎?抑或 Parent 和 Child 通過指針互指?Child 的生命期由 Parent 控制嗎?如果還有 ParentClub 和 School 兩個(gè) class,分別代表家長(zhǎng)俱樂部和學(xué)校:ParentClub has many Parent(s),School has many Child(ren),那么如何保證它們始終持有有效的 Parent 對(duì)象和 Child 對(duì)象?何時(shí)才能安全地釋放 Parent 和 Child ?

直接但是易錯(cuò)的寫法:

class Child;

class Parent : boost::noncopyable
{
 private:
  Child* myChild;
};

class Child : boost::noncopyable
{
 private:
  Parent* myParent;
};

如果直接使用指針作為成員,那么如何確保指針的有效性?如何防止出現(xiàn)空懸指針?Child 和 Parent 由誰負(fù)責(zé)釋放?在釋放某個(gè) Parent 對(duì)象的時(shí)候,如何確保程序中沒有指向它的指針?在釋放某個(gè) Child 對(duì)象的時(shí)候,如何確保程序中沒有指向它的指針?

這一系列問題一度是C++面向?qū)ο缶幊填^疼的問題,不過現(xiàn)在有了 smart pointer,我們可以借助 smart pointer 把對(duì)象語義轉(zhuǎn)換為值語義,從而輕松解決對(duì)象生命期:讓 Parent 持有 Child 的 smart pointer,同時(shí)讓 Child 持有 Parent 的 smart pointer,這樣始終引用對(duì)方的時(shí)候就不用擔(dān)心出現(xiàn)空懸指針。當(dāng)然,其中一個(gè) smart pointer 應(yīng)該是 weak reference,否則會(huì)出現(xiàn)循環(huán)引用,導(dǎo)致內(nèi)存泄漏。到底哪一個(gè)是 weak reference,則取決于具體應(yīng)用場(chǎng)景。

如果 Parent 擁有 Child,Child 的生命期由其 Parent 控制,Child 的生命期小于 Parent,那么代碼就比較簡(jiǎn)單:

class Parent;
class Child : boost::noncopyable
{
 public:
  explicit Child(Parent* myParent_)
    : myParent(myParent_)
  {
  }

 private:
  Parent* myParent;
};

class Parent : boost::noncopyable
{
 public:
  Parent()
    : myChild(new Child(this))
  {
  }

 private:
  boost::scoped_ptr<Child> myChild;
};

在上面這個(gè)設(shè)計(jì)中,Child 的指針不能泄露給外界,否則仍然有可能出現(xiàn)空懸指針。

如果 Parent 與 Child 的生命期相互獨(dú)立,就要麻煩一些:

class Parent;
typedef boost::shared_ptr<Parent> ParentPtr;

class Child : boost::noncopyable
{
 public:
  explicit Child(const ParentPtr& myParent_)
    : myParent(myParent_)
  {
  }

 private:
  boost::weak_ptr<Parent> myParent;
};
typedef boost::shared_ptr<Child> ChildPtr;


class Parent : public boost::enable_shared_from_this<Parent>,
               private boost::noncopyable
{
 public:
  Parent()
  {
  }

  void addChild()
  {
    myChild.reset(new Child(shared_from_this()));
  }

 private:
  ChildPtr myChild;
};

int main()
{
  ParentPtr p(new Parent);
  p->addChild();
}

上面這個(gè) shared_ptr+weak_ptr 的做法似乎有點(diǎn)小題大做。

考慮一個(gè)稍微復(fù)雜一點(diǎn)的對(duì)象模型:a Child has parents: mom and dad; a Parent has one or more Child(ren); a Parent knows his/her spouser. 這個(gè)對(duì)象模型用 Java 表述一點(diǎn)都不復(fù)雜,垃圾收集會(huì)幫我們搞定對(duì)象生命期。

public class Parent
{
    private Parent mySpouser;
    private ArrayList<Child> myChildren;
}

public class Child
{
    private Parent myMom;
    private Parent myDad;
}

如果用 C++ 來實(shí)現(xiàn),如何才能避免出現(xiàn)空懸指針,同時(shí)避免出現(xiàn)內(nèi)存泄漏呢?借助 shared_ptr 把裸指針轉(zhuǎn)換為值語義,我們就不用擔(dān)心這兩個(gè)問題了:

class Parent;
typedef boost::shared_ptr<Parent> ParentPtr;

class Child : boost::noncopyable
{
 public:
  explicit Child(const ParentPtr& myMom_,
                 const ParentPtr& myDad_)
    : myMom(myMom_),
      myDad(myDad_)
  {
  }

 private:
  boost::weak_ptr<Parent> myMom;
  boost::weak_ptr<Parent> myDad;
};
typedef boost::shared_ptr<Child> ChildPtr;

class Parent : boost::noncopyable
{
 public:
  Parent()
  {
  }

  void setSpouser(const ParentPtr& spouser)
  {
    mySpouser = spouser;
  }

  void addChild(const ChildPtr& child)
  {
    myChildren.push_back(child);
  }

 private:
  boost::weak_ptr<Parent> mySpouser;
  std::vector<ChildPtr> myChildren;
};

int main()
{
  ParentPtr mom(new Parent);
  ParentPtr dad(new Parent);
  mom->setSpouser(dad);
  dad->setSpouser(mom);
  {
    ChildPtr child(new Child(mom, dad));
    mom->addChild(child);
    dad->addChild(child);
  }
  {
    ChildPtr child(new Child(mom, dad));
    mom->addChild(child);
    dad->addChild(child);
  }
}

如果不使用 smart pointer,用 C++ 做面向?qū)ο缶幊虒?huì)困難重重。

值語義與標(biāo)準(zhǔn)庫

C++ 要求凡是能放入標(biāo)準(zhǔn)容器的類型必須具有值語義。準(zhǔn)確地說:type 必須是 SGIAssignable concept 的 model。但是,由 于C++ 編譯器會(huì)為 class 默認(rèn)提供 copy constructor 和 assignment operator,因此除非明確禁止,否則 class 總是可以作為標(biāo)準(zhǔn)庫的元素類型——盡管程序可以編譯通過,但是隱藏了資源管理方面的 bug。

因此,在寫一個(gè) class 的時(shí)候,先讓它繼承 boost::noncopyable,幾乎總是正確的。

在現(xiàn)代 C++ 中,一般不需要自己編寫 copy constructor 或 assignment operator,因?yàn)橹灰總€(gè)數(shù)據(jù)成員都具有值語義的話,編譯器自動(dòng)生成的 member-wise copying&assigning 就能正常工作;如果以 smart ptr 為成員來持有其他對(duì)象,那么就能自動(dòng)啟用或禁用 copying&assigning。例外:編寫 HashMap 這類底層庫時(shí)還是需要自己實(shí)現(xiàn) copy control。

值語義與C++語言

C++ 的 class 本質(zhì)上是值語義的,這才會(huì)出現(xiàn) object slicing 這種語言獨(dú)有的問題,也才會(huì)需要程序員注意 pass-by-value 和 pass-by-const-reference 的取舍。在其他面向?qū)ο缶幊陶Z言中,這都不需要費(fèi)腦筋。

值語義是C++語言的三大約束之一,C++ 的設(shè)計(jì)初衷是讓用戶定義的類型(class)能像內(nèi)置類型(int)一樣工作,具有同等的地位。為此C++做了以下設(shè)計(jì)(妥協(xié)):

  • class 的 layout 與 C struct 一樣,沒有額外的開銷。定義一個(gè)“只包含一個(gè) int 成員的 class ”的對(duì)象開銷和定義一個(gè) int 一樣。
  • 甚至 class data member 都默認(rèn)是 uninitialized,因?yàn)楹瘮?shù)局部的 int 是 uninitialized。
  • class 可以在 stack 上創(chuàng)建,也可以在 heap 上創(chuàng)建。因?yàn)?int 可以是 stack variable。
  • class 的數(shù)組就是一個(gè)個(gè) class 對(duì)象挨著,沒有額外的 indirection。因?yàn)?int 數(shù)組就是這樣。
  • 編譯器會(huì)為 class 默認(rèn)生成 copy constructor 和 assignment operator。其他語言沒有 copy constructor 一說,也不允許重載 assignment operator。C++ 的對(duì)象默認(rèn)是可以拷貝的,這是一個(gè)尷尬的特性。
  • 當(dāng) class type 傳入函數(shù)時(shí),默認(rèn)是 make a copy (除非參數(shù)聲明為 reference)。因?yàn)榘?int 傳入函數(shù)時(shí)是 make a copy。
  • 當(dāng)函數(shù)返回一個(gè) class type 時(shí),只能通過 make a copy(C++ 不得不定義 RVO 來解決性能問題)。因?yàn)楹瘮?shù)返回 int 時(shí)是 make a copy。
  • 以 class type 為成員時(shí),數(shù)據(jù)成員是嵌入的。例如 pair<complex<double>, size_t> 的 layout 就是 complex<double> 挨著 size_t。

這些設(shè)計(jì)帶來了性能上的好處,原因是 memory locality。比方說我們?cè)?C++ 里定義 complex<double> class,array of complex<double>, vector<complex<double> >,它們的 layout 分別是:(re 和 im 分別是復(fù)數(shù)的實(shí)部和虛部。)

value1

而如果我們?cè)?Java 里干同樣的事情,layout 大不一樣,memory locality 也差很多:

value2

Java 里邊每個(gè) object 都有 header,至少有兩個(gè) word 的開銷。對(duì)比 Java 和 C++,可見 C++ 的對(duì)象模型要緊湊得多。

待續(xù)

下一篇文章我會(huì)談與值語義緊密相關(guān)的數(shù)據(jù)抽象(data abstraction),解釋為什么它是與面向?qū)ο蟛⒘械囊环N編程范式,為什么支持面向?qū)ο蟮木幊陶Z言不一定支持?jǐn)?shù)據(jù)抽象。C++在最初的時(shí)候是以 data abstraction 為賣點(diǎn),不過隨著時(shí)間的流逝,現(xiàn)在似乎很多人只知 Object-Oriented,不知 data abstraction 了。C++ 的強(qiáng)大之處在于“抽象”不以性能損失為代價(jià),下一篇文章我們將看到具體例子。

posted on 2011-08-16 21:13 陳碩 閱讀(2815) 評(píng)論(4)  編輯 收藏 引用

評(píng)論

# re: C++ 工程實(shí)踐(8):值語義 2011-08-17 08:51 nk_ysg

學(xué)習(xí)下,lz這么久才更新。  回復(fù)  更多評(píng)論   

# re: C++ 工程實(shí)踐(8):值語義 2011-08-17 12:17 江浸月

樓主大牛啊,坐等樓主更新新文章。  回復(fù)  更多評(píng)論   

# re: C++ 工程實(shí)踐(8):值語義[未登錄] 2011-08-24 12:11 Chipset

shared_ptr, weak_ptr是廢物,除了降低速度和吃掉更多內(nèi)存,我沒有見到什么好處。C++的析構(gòu)函數(shù)可以以很小的代價(jià)避免很多資源管理方面的問題,但是為了遷就太多不熟悉C++的人不得不納入標(biāo)準(zhǔn)。

就算為了尊重人權(quán)允許用垃圾收集,引用計(jì)數(shù)設(shè)計(jì)的垃圾收集跟保守的標(biāo)記清理似乎沒有發(fā)現(xiàn)什么優(yōu)勢(shì),看看Boehm吧。

把C++當(dāng)Java用可能是最傻的事情,可惜太多程序員正在這么干,專門喜歡垃圾用法。

OO在歐美的上世紀(jì)七十年代就被看成雞肋,可惜亞太地區(qū)尤其中國很多程序員拿過來當(dāng)寶貝,加上腐朽的科技支持力度,導(dǎo)致了太多的悲哀,IT技術(shù)水平跟歐美距離越來越大,而且加速拉大...  回復(fù)  更多評(píng)論   

# re: C++ 工程實(shí)踐(8):值語義 2011-08-31 08:40 Neuron Teckid

看標(biāo)題還以為陳老師會(huì)談新標(biāo)準(zhǔn)中的 left value 和 rvalue reference. 不過有些東西還是很相通的, 比如對(duì)象復(fù)制構(gòu)造在 cpp 中被嚴(yán)重濫用了, 大部分對(duì)象不應(yīng)當(dāng)有 "復(fù)制" 這樣的操作, 更多的是 "轉(zhuǎn)移", 我認(rèn)為 c++0x 的 rvalue reference 正是為了修正這個(gè) cpp 一直以來的設(shè)計(jì)漏洞產(chǎn)生的. 包括后面標(biāo)準(zhǔn)庫中 vector 對(duì)成員的要求也從 assignable and copyable 變成了 (assignable and copyable) or movable.

至于內(nèi)存管理, 這個(gè)比較虛, 如果真有非常離奇復(fù)雜的對(duì)象引用關(guān)系, 是不是考慮該修改設(shè)計(jì)本身了, 反正我個(gè)人經(jīng)歷接觸的對(duì)象模型多以樹形為主, 很少有 parent / child 這樣互搞的 :D  回復(fù)  更多評(píng)論   


只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


<2011年8月>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

導(dǎo)航

統(tǒng)計(jì)

常用鏈接

隨筆分類

隨筆檔案

相冊(cè)

搜索

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久三级视频| 老司机aⅴ在线精品导航| 激情久久影院| 日韩午夜剧场| 久久久福利视频| 亚洲美女少妇无套啪啪呻吟| 久久久久成人精品| 国产精品一区在线观看| 日韩一区二区精品葵司在线| 免费成人高清| 欧美一级淫片播放口| 国产精品中文字幕欧美| 一区二区三区欧美在线观看| 亚洲第一主播视频| 性感少妇一区| 国产精品美女www爽爽爽| 欧美在线啊v| 国产欧美日韩在线视频| 日韩天堂在线观看| 亚洲狠狠婷婷| 欧美日本成人| 99亚洲伊人久久精品影院红桃| 久久久久久久综合狠狠综合| 亚洲欧美色一区| 国产在线高清精品| 久久久久久久欧美精品| 欧美在线视频一区二区| 国产精品视频999| 亚洲一区欧美激情| 99精品国产福利在线观看免费 | 亚洲欧洲一区二区在线观看| 欧美xx视频| 亚洲香蕉伊综合在人在线视看| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 欧美一区二区三区视频在线| 欧美激情亚洲自拍| 亚洲综合丁香| 永久免费毛片在线播放不卡| 欧美激情 亚洲a∨综合| 欧美理论大片| 欧美一区91| 欧美顶级大胆免费视频| aa级大片欧美| 欧美一区二区| 亚洲伦理久久| 亚洲欧美日韩精品久久久久| 亚洲丰满在线| 亚洲图片你懂的| 在线观看视频免费一区二区三区| 欧美大片网址| 国产精品日韩欧美综合| 欧美www视频| 国产精品久久二区| 免费成人在线视频网站| 欧美午夜一区二区三区免费大片 | 久久久久99| 这里只有精品视频在线| 欧美一区1区三区3区公司| 亚洲精品资源美女情侣酒店| 亚洲免费视频成人| 亚洲精品欧美| 久久精品国产精品亚洲综合| 夜夜嗨av一区二区三区网页| 中文在线不卡视频| 亚洲区第一页| 欧美在线综合视频| 亚洲综合999| 欧美激情一区| 欧美77777| 久久精品九九| 亚洲一区在线免费| 欧美电影在线观看完整版| 久久综合九色99| 国产精品男gay被猛男狂揉视频| 亚洲高清视频在线观看| 黄色日韩网站视频| 欧美一级大片在线观看| 亚洲女女做受ⅹxx高潮| 欧美日韩国产色站一区二区三区| 免费成人高清在线视频| 国精品一区二区三区| 亚洲自拍偷拍福利| 亚洲先锋成人| 欧美性感一类影片在线播放| 最新国产成人在线观看| 亚洲黑丝在线| 久热精品视频在线| 免费在线看成人av| 影音先锋欧美精品| 久久久久99| 欧美福利一区二区三区| 在线播放中文字幕一区| 欧美亚洲在线播放| 久久精品视频在线看| 国产精品一级| 午夜精品福利视频| 久久激情中文| 国产一区91| 久久精品国产视频| 女女同性精品视频| 亚洲欧洲综合另类在线| 欧美另类视频在线| 99re6热在线精品视频播放速度| 一本色道精品久久一区二区三区| 欧美激情久久久| 一区二区欧美日韩| 午夜亚洲伦理| 好吊妞**欧美| 免费人成网站在线观看欧美高清 | 欧美国产欧美亚洲国产日韩mv天天看完整| 免费在线成人av| 亚洲日本欧美| 欧美视频在线视频| 亚洲在线播放| 久久蜜臀精品av| 亚洲人成在线影院| 欧美日韩亚洲系列| 亚洲欧美综合v| 欧美.www| 亚洲视频中文| 国产婷婷色一区二区三区四区| 久久精品卡一| 亚洲美女视频在线免费观看| 亚洲欧美一区二区三区久久| 国内精品国产成人| 欧美精品黄色| 亚洲精品日本| 欧美一进一出视频| 久热精品视频在线观看| 亚洲黄色免费电影| 欧美日韩精品不卡| 亚洲欧美自拍偷拍| 欧美风情在线观看| 亚洲一区二区免费| 国产一区二区三区的电影 | 亚洲国产精品传媒在线观看 | 亚洲精品视频在线看| 国产精品久久久久久久久久免费 | 欧美日韩中文字幕综合视频| 午夜视频一区在线观看| 亚洲国产精品一区二区久| 亚洲欧美一区二区在线观看| 亚洲国语精品自产拍在线观看| 国产精品久久久久久久久久三级 | 亚洲美女诱惑| 久久在线播放| 亚洲欧美在线一区| 亚洲精品国产拍免费91在线| 国产婷婷一区二区| 欧美视频在线观看视频极品| 久久综合色影院| 午夜精品一区二区三区四区 | 久久一二三四| 欧美一区二区三区免费视频| 日韩视频永久免费观看| 欧美va亚洲va日韩∨a综合色| 欧美亚洲午夜视频在线观看| 亚洲美女精品一区| 在线观看视频欧美| 黄色日韩在线| 国产一区二区三区自拍| 国产精品久久久久久久久婷婷| 欧美激情综合五月色丁香小说| 久久精品免费电影| 欧美一区二区视频网站| 亚洲午夜视频| 一区二区三区四区五区视频| 欧美国产亚洲视频| 免费欧美视频| 农村妇女精品| 亚洲电影免费观看高清完整版在线观看 | 欧美一级二级三级蜜桃| 99国产麻豆精品| 亚洲第一在线| 永久久久久久| 在线观看日韩专区| 亚洲电影免费| 亚洲电影免费观看高清完整版在线观看 | 国产日韩欧美综合一区| 国产精品色婷婷| 国产伦精品一区二区三区免费迷| 国产精品久久久久久久久久三级 | 国产精品欧美日韩| 国产精品美女久久久久久久 | 亚洲综合第一| 午夜在线播放视频欧美| 欧美一区二区精品| 久久久.com| 免费久久精品视频| 亚洲国产天堂久久国产91| 亚洲人午夜精品| 一本色道久久综合亚洲二区三区| 一本大道久久精品懂色aⅴ| 一本色道久久综合一区| 亚洲免费中文字幕| 久久成人这里只有精品| 久久精品国产999大香线蕉| 噜噜噜久久亚洲精品国产品小说| 麻豆国产精品777777在线| 欧美激情久久久|