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

隨筆-341  評(píng)論-2670  文章-0  trackbacks-0
    復(fù)雜的東西寫(xiě)多了,如今寫(xiě)點(diǎn)簡(jiǎn)單的好了。由于功能上的需要,Vczh Library++3.0被我搞得很離譜。為了開(kāi)發(fā)維護(hù)的遍歷、減少粗心犯下的錯(cuò)誤以及增強(qiáng)單元測(cè)試、回歸測(cè)試和測(cè)試工具,因此記錄下一些開(kāi)發(fā)上的小技巧,以便拋磚引玉,造福他人。歡迎高手來(lái)噴,菜鳥(niǎo)膜拜。

    上一篇文章講到了如何檢查內(nèi)存泄露。其實(shí)只要肯用C++的STL里面的高級(jí)功能的話,內(nèi)存泄露是很容易避免的。我在開(kāi)發(fā)Vczh Library++ 3.0的時(shí)候,所有的測(cè)試用例都保證跑完了沒(méi)有內(nèi)存泄露。但是很可惜有些C++團(tuán)隊(duì)不能使用異常,更甚者不允許寫(xiě)構(gòu)造函數(shù)析構(gòu)函數(shù)之類(lèi),前一個(gè)還好,后一個(gè)簡(jiǎn)直就是在用C。當(dāng)然有這些變態(tài)規(guī)定的地方STL都是用不了的,所以我們更加需要扎實(shí)的基礎(chǔ)來(lái)開(kāi)發(fā)C++程序。

    今天這一篇主要還是講指針的問(wèn)題。因?yàn)樯弦黄恼乱还P帶過(guò),今天就來(lái)詳細(xì)講內(nèi)存泄漏或者野指針發(fā)生的各種情況。當(dāng)然我不可能一下子舉出全部的例子,只能說(shuō)一些常見(jiàn)的。

    一、錯(cuò)誤覆蓋內(nèi)存。

    之前提到的不能隨便亂memset其實(shí)就是為了避免這個(gè)問(wèn)題的。其實(shí)memcpy也不能亂用,我們來(lái)看一個(gè)例子,最簡(jiǎn)單的:
 1 #define MAX_STRING 20;
 2 
 3 struct Student
 4 {
 5   char name[MAX_STRING];
 6   char id[MAX_STRING];
 7   int chinese;
 8   int math;
 9   int english;
10 };

    大家對(duì)這種結(jié)構(gòu)肯定十分熟悉,畢竟是大學(xué)時(shí)候經(jīng)常要寫(xiě)的作業(yè)題……好了,大家很容易看得出來(lái)這其實(shí)是C語(yǔ)言的經(jīng)典寫(xiě)法。我們拿到手之后,一般會(huì)先初始化一下,然后賦值。
1 Student vczh;
2 memset(&vczh, 0sizeof(vczh));
3 strcpy(vczh.name, "vczh");
4 strcpy(vczh.id, "VCZH'S ID");
5 vczh.chinese=70;
6 vczh.math=90;
7 vczh.english=80;

    為什么要在這里使用memset呢?memset的用處是將一段內(nèi)存的每一個(gè)字節(jié)都設(shè)置成同一個(gè)數(shù)字。這里是0,因此兩個(gè)字符串成員的所有字節(jié)都會(huì)變成0。因此在memset了Student之后,我們通過(guò)正常方法來(lái)訪問(wèn)name和id的時(shí)候都會(huì)得到空串。而且如果Student里面有指針的話,0指針代表的是沒(méi)有指向任何有效對(duì)象,因此這個(gè)時(shí)候?qū)χ羔樦赶虻膶?duì)象進(jìn)行讀寫(xiě)就會(huì)立刻崩潰。對(duì)于其他數(shù)值,0一般作為初始值也不會(huì)有什么問(wèn)題(double什么的要小心)。這就是我們寫(xiě)程序的時(shí)候使用memset的原因。

    好了,如今社會(huì)進(jìn)步,人民當(dāng)家做主了,死程們?cè)僖膊恍枰艿娇蓯旱腃語(yǔ)言剝削了,我們可以使用C++!因此我們借助STL的力量把Student改寫(xiě)成下面這種帶有C++味道的形式:
1 struct Student
2 {
3   std::string name;
4   std::string id;
5   int chinese;
6   int math;
7   int english;
8 };

    我們?nèi)匀恍枰獙?duì)Student進(jìn)行初始化,不然三個(gè)分?jǐn)?shù)還是隨機(jī)值。但是我們又不想每一次創(chuàng)建的時(shí)候都對(duì)他們分別進(jìn)行賦值初始化城0。這個(gè)時(shí)候你心里可能還是想著memset,這就錯(cuò)了!在memset的時(shí)候,你會(huì)把std::string內(nèi)部的不知道什么東西也給memset掉。假如一個(gè)空的std::string里面存放的指針指向的是一個(gè)空的字符串而不是用0來(lái)代表空的時(shí)候,一下子內(nèi)部的指針就被你刷成0,等下std::string的析構(gòu)函數(shù)就沒(méi)辦法delete掉指針了,于是內(nèi)存泄露就出現(xiàn)了。有些朋友可能不知道上面那句話說(shuō)的是什么意思,我們現(xiàn)在來(lái)模擬一下不能memset的std::string要怎么實(shí)現(xiàn)。

    為了讓memset一定出現(xiàn)內(nèi)存泄露,那么std::string里面的指針必須永遠(yuǎn)都指向一個(gè)有效的東西。當(dāng)然我們還需要在字符串進(jìn)行復(fù)制的時(shí)候復(fù)制指針。我們這里不考慮各種優(yōu)化技術(shù),用最簡(jiǎn)單的方法做一個(gè)字符串出來(lái):
 1 class String
 2 {
 3 private:
 4   char* buffer;
 5 
 6 public:
 7   String()
 8   {
 9     buffer=new char[1];
10     buffer[0]=0;
11   }
12 
13   String(const char* s)
14   {
15     buffer=new char[strlen(s)+1];
16     strcpy(buffer, s);
17   }
18 
19   String(const String& s)
20   {
21     buffer=new char[strlen(s.buffer)+1];
22     strcpy(buffer, s.buffer);
23   }
24 
25   ~String()
26   {
27     delete[] buffer;
28   }
29 
30   String& operator=(const String& s)
31   {
32     delete[] buffer;
33     buffer=new char[strlen(s.buffer)+1];
34     strcpy(buffer, s.buffer);
35   }
36 };

    于是我們來(lái)做一下memset。首先定義一個(gè)字符串變量,其次memset掉,讓我們看看會(huì)發(fā)生什么事情:
1 string s;
2 memset(&s, 0sizeof(s));

    第一行我們構(gòu)造了一個(gè)字符串s。這個(gè)時(shí)候字符串的構(gòu)造函數(shù)就會(huì)開(kāi)始運(yùn)行,因此strcmp(s.buffer, "")==0。第二行我們把那個(gè)字符串給memset掉了。這個(gè)時(shí)候s.buffer==0。于是函數(shù)結(jié)束了,字符串的析構(gòu)函數(shù)嘗試delete這個(gè)指針。我們知道delete一個(gè)0是不會(huì)有問(wèn)題的,因此程序不會(huì)發(fā)生錯(cuò)誤。我們活生生把構(gòu)造函數(shù)賦值給buffer的new char[1]給丟了!鐵定發(fā)生內(nèi)存泄露!

    好了,提出問(wèn)題總要解決問(wèn)題,我們不使用memset的話,怎么初始化Student呢?這個(gè)十分好做,我們只需要為Student加上構(gòu)造函數(shù)即可:
1 struct Student
2 {
3   .//不重復(fù)那些聲明
4 
5   Student():chinese(0),math(0),english(0)
6   {
7   }
8 };

    這樣就容易多了。每當(dāng)我們定義一個(gè)Student變量的時(shí)候,所有的成員都初始化好了。name和id因?yàn)閟tring的構(gòu)造函數(shù)也自己初始化了,因此所有的成員也都初始化了。加入Student用了一半我們想再初始化一下怎么辦呢?也很容易:
1 Student vczh;
2 .//各種使用
3 vczh=Student();

    經(jīng)過(guò)一個(gè)等號(hào)操作符的調(diào)用,舊Student的所有成員就被一個(gè)新的初始化過(guò)的Student給覆蓋了,就如同我們對(duì)一個(gè)int變量重新賦值一樣常見(jiàn)。當(dāng)然因?yàn)楦鞣N復(fù)制經(jīng)常會(huì)出現(xiàn),因此我們也要跟上面貼出來(lái)的string的例子一樣,實(shí)現(xiàn)好那4個(gè)函數(shù)。至此我十分不理解為什么某些團(tuán)隊(duì)不允許使用構(gòu)造函數(shù),我猜就是為了可以memset,其實(shí)是很沒(méi)道理的。

    二、異常。

    咋一看內(nèi)存泄露跟異常好像沒(méi)什么關(guān)系,但實(shí)際上這種情況更容易發(fā)生。我們來(lái)看一個(gè)例子:
 1 char* strA=new char[MAX_PATH];
 2 if(GetXXX(strA, MAX_PATH)==ERROR) goto RELEASE_STRA;
 3 char* strB=new char[MAX_PATH];
 4 if(GetXXX(strB, MAX_PATH)==ERROR) goto RELEASE_STRB;
 5 
 6 DoSomething(strA, strB);
 7 
 8 RELEASE_STRB:
 9 delete[] strB;
10 RELEASE_STRA:
11 delete[] strA;

    相信這肯定是大家的常用模式。我在這里也不是教唆大家使用goto,不過(guò)對(duì)于這種例子來(lái)說(shuō),用goto是最優(yōu)美的解決辦法了。但是大家可以看出來(lái),我們用的是C++,因?yàn)檫@里有new。如果DoSomething發(fā)生了異常怎么辦呢?如果GetXXX發(fā)生了異常怎么辦呢?我們這里沒(méi)有任何的try-catch,一有異常,函數(shù)里克結(jié)束,兩行可憐的delete就不會(huì)被執(zhí)行到了,于是內(nèi)存泄漏發(fā)生了

    那我們?nèi)绾伪苊膺@種情況下的內(nèi)存泄露呢?一些可愛(ài)的小盆友可能會(huì)想到,既然是因?yàn)闆](méi)有catch異常才發(fā)生的內(nèi)存泄露,那我們來(lái)catch吧:
 1 char* strA=new char[MAX_PATH];
 2 try
 3 {
 4   if(GetXXX(strA, MAX_PATH)==ERROR) goto RELEASE_STRA;
 5   char* strB=new char[MAX_PATH];
 6   try
 7   {
 8     if(GetXXX(strB, MAX_PATH)==ERROR) goto RELEASE_STRB;
 9     DoSomething(strA, strB);
10   }
11   catch()
12   {
13     delete[] strB;
14     throw;
15   }
16 }
17 catch()
18 {
19   delete[] strA;
20   throw;
21 }
22 
23 RELEASE_STRB:
24 delete[] strB;
25 RELEASE_STRA:
26 delete[] strA;

    你能接受嗎?當(dāng)然是不能的。問(wèn)題出在哪里呢?因?yàn)镃++沒(méi)有try-finally。你看這些代碼到處都是雷同的東西,顯然我們需要編譯器幫我們把這些問(wèn)題搞定。最好的解決方法是什么呢?顯然還是構(gòu)造函數(shù)和析構(gòu)函數(shù)。總之記住,如果想要事情成對(duì)發(fā)生,那么使用構(gòu)造函數(shù)和析構(gòu)函數(shù)

    第一步,GetXXX顯然只能支持C模式的東西,因此我們要寫(xiě)一個(gè)支持C++的:
 1 bool GetXXX2(string& s)
 2 {
 3   char* str=new char[MAX_PATH];
 4   bool result;
 5   try
 6   {
 7     result=GetXXX(str, MAX_PATH);
 8     if(result)s=str;
 9   }
10   catch()
11   {
12     delete[] str;
13     throw;
14   }
15   delete[] str;
16   return result;
17 }

    借助這個(gè)函數(shù)我們可以看到,因?yàn)橛辛薌etXXX這種C的東西,導(dǎo)致我們多了多少麻煩。不過(guò)這總是一勞永逸的,有了GetXXX2和修改之后的DoSomething2之后,我們就可以用更簡(jiǎn)單的方法來(lái)做了:
1 string a,b;
2 if(GetXXX2(a) && GetXXX2(b))
3 {
4   DoSomething2(a, b);
5 }

    多么簡(jiǎn)單易懂。這個(gè)代碼在任何地方發(fā)生了異常,所有new的東西都會(huì)被delete。這就是析構(gòu)函數(shù)的一個(gè)好處。一個(gè)變量的析構(gòu)函數(shù)在這個(gè)變量超出了作用域的時(shí)候一定會(huì)被調(diào)用,無(wú)論代碼是怎么走出去的。

    今天就說(shuō)到這里了。說(shuō)了這么多還是想讓大家不要小看構(gòu)造函數(shù)和析構(gòu)函數(shù)。那種微不足道的因?yàn)橐恍〔糠植皇瞧款i的性能問(wèn)題而放棄構(gòu)造函數(shù)和析構(gòu)函數(shù)的做法,終究是要為了修bug而加班的。只要明白并用好了構(gòu)造函數(shù)、析構(gòu)函數(shù)和異常,那么C++的特性也可以跟C一樣清楚明白便于理解,而且寫(xiě)出來(lái)的代碼更好看的。大家期待第三篇哈。
posted on 2010-06-23 10:12 陳梓瀚(vczh) 閱讀(11742) 評(píng)論(23)  編輯 收藏 引用 所屬分類(lèi): C++實(shí)用技巧

評(píng)論:
# re: C++實(shí)用技巧(二) 2010-06-23 12:53 | OwnWaterloo
>>0指針代表的是沒(méi)有指向任何有效對(duì)象

空指針的二進(jìn)制表示并不一定是全0 。
浮點(diǎn)數(shù)也一樣, 0.0f, 0.0, 0.0lf的二進(jìn)制表示都不一定是全0。
所以, 即使是C語(yǔ)言, 欲使用memset去將指針初始化為空, 或者將浮點(diǎn)初始化為0, 都是不可移植的。


>>30 String& operator=(const String& s)
>>31 {
>>32 delete[] buffer;
>>33 buffer=new char[strlen(s.buffer)+1];
>>34 strcpy(buffer, s.buffer);
>>35 }

這個(gè)實(shí)現(xiàn)有問(wèn)題, 當(dāng)出現(xiàn)自賦值的時(shí)候:
String s;
s = s;
this->buffer和s.buffer是同一個(gè)指針。
32行delete之后, 已經(jīng)是dangling pointer。
33行傳遞給strlen, 34行傳遞給strcpy都是錯(cuò)誤的。


要么判斷自賦值的情況:
if (this!=&s)
{
delete[] buffer;
size_t len = strlen(s.buffer)+1;
buffer = new char[ len ];
memcpy(buffer, s.buffer, len );
}

但是, 如果new新的buffer時(shí)出現(xiàn)異常, 就會(huì)導(dǎo)致this有一個(gè)dangling pointer。
為了安全, 可以先new, 再delete:
size_t len = strlen(s.buffer)+1;
char* p = new char[len]; // 之后操作都不會(huì)產(chǎn)生異常
memcpy(p, s.buffer, len );
delete[] buffer;
buffer = p;

先new再delete也可以不用判斷自賦值的情況了。
  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 17:55 | zuhd
@OwnWaterloo
哥,你總是這么犀利,我給你留言看到?jīng)]?  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 18:33 | OwnWaterloo
@zuhd
剛發(fā)現(xiàn)…… 那一天收到的通知太多, 被我直接全部標(biāo)記為已讀, 然后忘了……
通常用同名gmail郵箱, qq不怎么用……
  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 18:42 | 陳梓瀚(vczh)
@OwnWaterloo
為了迅速說(shuō)明問(wèn)題,那個(gè)string其實(shí)還有很多其他的缺陷的……因?yàn)樵谥笾v構(gòu)造函數(shù)和析構(gòu)函數(shù)的一篇上會(huì)著重處理這種case。

話說(shuō)回來(lái),我上一篇提到了,這個(gè)系列是默認(rèn)你使用Visual C++的。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 18:46 | 陳梓瀚(vczh)
@OwnWaterloo
話說(shuō)回來(lái),因?yàn)樵贑++里面,字面量“0”的確是代表空指針,因此如果空指針的二進(jìn)制真的不是0的話,我可以認(rèn)為是編譯器的bug。因?yàn)閺恼Z(yǔ)法上講,既然void* p=0;是對(duì)的,那么void* p=(void*)(int)0;也必須是對(duì)的。

除非從一開(kāi)始就有C++0x的nullptr。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 19:25 | OwnWaterloo
@陳梓瀚(vczh)
無(wú)論是C還是C++, 說(shuō)的都是"編譯時(shí)可求出0值的常數(shù)是空指針常量"。
可以將空指針賦值給任意指針類(lèi)型的變量。
但并不保證賦值之后指針變量的二進(jìn)制表示也是全0。


從語(yǔ)法上講:
void* p = 0;
void* p=(void*)(int)0;
都是對(duì)的, 就像:

float f = 0;
float f = (float)(int)0;
而通常f的二進(jìn)制表示并不是全0。
這是因?yàn)榫幾g器是能看到這里的轉(zhuǎn)型動(dòng)作, 并加入適當(dāng)?shù)牟僮鳌?br>

但這樣寫(xiě)就是沒(méi)有保證的:
void* p;
memset(&p, 0, sizeof p);
memset函數(shù)中已經(jīng)不知道p的類(lèi)型, 只能將p當(dāng)作byte 數(shù)組。
就沒(méi)有機(jī)會(huì)為指針類(lèi)型作適當(dāng)?shù)恼{(diào)整。


再舉個(gè)例子:
class A {};
class B {};
class C : public A, public B {};

C c;
C* pc = &c;
A* pa = pc;
B* pb = pc;
assert( pc==pa && pc==pb);

因?yàn)榫幾g器知道pc,pa,pb的類(lèi)型。
所以無(wú)論是賦值還是比較, 都會(huì)插入適當(dāng)?shù)牟僮鳌?br>
而如果使用memset或者memcmp, 就掛了。


最后, 標(biāo)準(zhǔn)中有句話, 在calloc的腳注里。
The calloc function allocates space for an array
of nmemb objects, each of whose size is size.
The space is initialized to all bits zero.

Note that this need not be the same as the representation
of floating-point zero or a null pointer constant.
  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 20:40 | 付翔
指出個(gè) 小錯(cuò)誤
#define MAX_STRING 20; 不要分號(hào)   回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 21:49 | 陳梓瀚(vczh)
@OwnWaterloo
話說(shuō)回來(lái),那什么地方的空指針的二進(jìn)制不是0?  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 21:50 | 陳梓瀚(vczh)
@付翔
嗯嗯,這是個(gè)錯(cuò)誤。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 21:52 | 陳梓瀚(vczh)
@OwnWaterloo
不過(guò)這個(gè)二進(jìn)制位不是0的事實(shí)更加反映出了構(gòu)造函數(shù)的重要性,memset更加不能隨便來(lái)了(當(dāng)然指的是非Visual C++的情況)  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 22:12 | OwnWaterloo
@陳梓瀚(vczh)
http://linuxdude.com/Steve_Sumit/C-faq/q5.17.html
整個(gè)第5章都是講null pointer的。
  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-23 22:35 | 陳梓瀚(vczh)
@OwnWaterloo
都是些從現(xiàn)在開(kāi)始見(jiàn)都沒(méi)見(jiàn)過(guò)的機(jī)器……  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-24 01:18 | 匿名
delete null
確定程序不會(huì)拋異常?  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-24 01:46 | 匿名(還是俺)
char* strA=new char[MAX_PATH];
這個(gè)也不能保證它一定不會(huì)拋異常。
new這個(gè)數(shù)組的時(shí)候,加入new到第M個(gè)(M小于MAX_PATH)時(shí)候拋出異常,這時(shí)候也會(huì)有內(nèi)存泄露咯  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-24 03:28 | 陳梓瀚(vczh)
@匿名(還是俺)
如果new一個(gè)東西還是敗了,那程序就直接log了崩潰了吧  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-24 10:25 | paul_simon
1 string s;
2 memset(&s, 0, sizeof(s));
//這里有個(gè)問(wèn)題想和博主探討,下文中提到的buffer是String的一個(gè)private成
//員,memset函數(shù)是不是該在String的成員函數(shù)里面調(diào)用,比如:
String::mems()
{
memset(buffer,0,sizeof(buffer));
}
//或者可否考慮在String::String()里加入memset函數(shù)
//QQ:29975723,謝謝  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-24 21:00 | 陳梓瀚(vczh)
@paul_simon
String當(dāng)然要為自己負(fù)責(zé)了,如果String自己覺(jué)得memset合適,那當(dāng)然可以。不過(guò)你那么搞有問(wèn)題,除非buffer是一個(gè)數(shù)組而不是指針。

但是外部不能memset掉string。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-25 01:07 | paul_simon
@陳梓瀚(vczh)
String的構(gòu)造函數(shù)決定了buffer是個(gè)數(shù)組,這里的String和student是兩個(gè)不同的對(duì)象,String里的buffer成員不能被外部的memset所清零吧?
所以我說(shuō)的是
1 string s;
2 memset(&s, 0, sizeof(s));//這里的實(shí)質(zhì)不是是對(duì)buffer進(jìn)行清零嗎?  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-25 05:43 | 陳梓瀚(vczh)
@paul_simon
不是,因?yàn)轭?lèi)的私有部分是不透明的,所以你在外部操作的時(shí)候,不能以知道string的實(shí)現(xiàn)作為前提,人家改了怎么辦,你就要加班了。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-28 02:11 | 球球
如果memset用在子類(lèi)的初始化時(shí)...  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-28 03:22 | 陳梓瀚(vczh)
@球球
子類(lèi)也不能假設(shè)父類(lèi)是如何實(shí)現(xiàn)的。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-29 00:06 | chenq
用那么多代碼去try catch那個(gè)GetXXX,為什么不直接用smart pointer呢  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(二) 2010-06-29 09:58 | 陳梓瀚(vczh)
@chenq
因?yàn)橛昧藄mart pointer就不能告訴人們C風(fēng)格的丑陋  回復(fù)  更多評(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>
            欧美日韩亚洲视频一区| 免费永久网站黄欧美| 国产精品永久入口久久久| 亚洲欧美一区二区精品久久久| 99视频精品全部免费在线| 国产精品99免费看| 欧美中文在线视频| 久久久久久久尹人综合网亚洲| 在线日韩电影| 99国产精品国产精品久久| 国产伦精品一区二区三区高清| 久久久精彩视频| 乱中年女人伦av一区二区| 亚洲视频电影在线| 香蕉av福利精品导航| 亚洲激情黄色| 亚洲性xxxx| 亚洲国产国产亚洲一二三| 亚洲乱码国产乱码精品精可以看| 国产精品高潮呻吟视频| 欧美成人a∨高清免费观看| 欧美日韩裸体免费视频| 久久久免费观看视频| 欧美日韩国内自拍| 久久这里有精品15一区二区三区| 欧美激情一区二区三区| 久久精品1区| 欧美日韩午夜激情| 欧美aaa级| 欧美成人日韩| 亚洲男人第一网站| 91久久精品美女高潮| 亚洲影视九九影院在线观看| 亚洲国产欧美日韩| 亚洲自拍16p| 亚洲一区bb| 欧美国产日产韩国视频| 久久久久一区| 国产精品视频| 日韩网站在线看片你懂的| 1000精品久久久久久久久| 亚洲免费一级电影| 中文国产成人精品久久一| 美女国产一区| 欧美18av| 今天的高清视频免费播放成人 | 一本色道久久精品| 亚洲欧洲免费视频| 久久手机免费观看| 久久综合成人精品亚洲另类欧美| 国产精品高清在线观看| 亚洲最新色图| 中文国产亚洲喷潮| 欧美日韩午夜| 一本色道久久综合狠狠躁篇的优点 | 一区二区三区av| 亚洲一本大道在线| 欧美日韩人人澡狠狠躁视频| 亚洲高清视频的网址| 韩国亚洲精品| 久久久久久欧美| 欧美a级片网站| 亚洲福利视频专区| 免费试看一区| 亚洲欧洲一区二区天堂久久| 亚洲精品偷拍| 欧美日韩亚洲一区二区三区在线观看 | 国产日韩一级二级三级| 亚洲男女自偷自拍| 性欧美长视频| 国内精品久久久久影院优| 久久精品人人做人人综合| 欧美14一18处毛片| 日韩亚洲欧美成人一区| 欧美色视频日本高清在线观看| 日韩午夜在线视频| 欧美一区二区三区电影在线观看| 国产精品美女久久久浪潮软件| 亚洲欧美大片| 免费在线成人av| 99riav国产精品| 国产精品看片资源| 久久精品视频在线免费观看| 欧美电影资源| 亚洲一级免费视频| 亚洲精品乱码久久久久久日本蜜臀 | 欧美在线看片| 亚洲高清视频在线观看| 亚洲无线视频| 国产一区二区| 欧美激情视频一区二区三区不卡| 亚洲人成网站在线播| 销魂美女一区二区三区视频在线| 国语精品中文字幕| 欧美精品在线免费| 午夜久久影院| 亚洲片区在线| 久久蜜桃精品| 亚洲一区bb| 亚洲国产清纯| 国产亚洲福利一区| 欧美乱妇高清无乱码| 欧美在线观看视频在线| 99re8这里有精品热视频免费 | 亚洲高清一区二| 久久动漫亚洲| 亚洲一区二区三区激情| 伊人婷婷欧美激情| 国产精品一区二区三区免费观看| 久热国产精品视频| 先锋影院在线亚洲| 一区二区av在线| 亚洲国产欧美不卡在线观看| 欧美在线一区二区三区| 亚洲一区二区日本| 亚洲精品乱码久久久久久黑人| 国产日韩精品在线播放| 欧美色网一区二区| 欧美精品久久一区| 蜜臀久久99精品久久久画质超高清| 午夜欧美不卡精品aaaaa| aa级大片欧美| 亚洲国产小视频| 女人色偷偷aa久久天堂| 久久久久久一区二区| 性欧美大战久久久久久久久| 在线视频日本亚洲性| 日韩亚洲成人av在线| 亚洲国产一区二区三区青草影视 | 欧美日韩国产成人| 欧美黄色成人网| 欧美成人在线免费视频| 美女网站久久| 久久综合影视| 免费久久99精品国产自在现线| 久久久99免费视频| 欧美在线网站| 久久精品久久99精品久久| 欧美伊人久久| 久久久久久免费| 美女999久久久精品视频| 蜜臀久久久99精品久久久久久| 猛男gaygay欧美视频| 母乳一区在线观看| 欧美 日韩 国产一区二区在线视频| 巨乳诱惑日韩免费av| 久久亚洲综合色| 欧美承认网站| 欧美色欧美亚洲另类七区| 国产精品久久久爽爽爽麻豆色哟哟 | av成人免费观看| 亚洲一区二区三区三| 亚洲欧美激情诱惑| 久久福利一区| 欧美成人国产一区二区| 亚洲午夜日本在线观看| 国产日产精品一区二区三区四区的观看方式| 国产精品久久久久久久电影| 国产精品久久久久永久免费观看| 国产欧美日本一区二区三区| 国产一区二区三区精品欧美日韩一区二区三区 | 久久蜜桃精品| 欧美日韩国产小视频在线观看| 欧美色大人视频| 国语自产偷拍精品视频偷 | 一区二区不卡在线视频 午夜欧美不卡在 | 在线不卡中文字幕播放| 日韩亚洲精品在线| 香蕉免费一区二区三区在线观看| 久久久久久久久久看片| 亚洲福利在线视频| 亚洲尤物视频在线| 久久这里只有| 国产精品免费视频xxxx| 曰韩精品一区二区| 亚洲在线视频| 嫩模写真一区二区三区三州| 亚洲毛片在线看| 久久全国免费视频| 国产精品看片你懂得| 亚洲狠狠婷婷| 久久精品国产亚洲a| 亚洲人午夜精品免费| 香蕉视频成人在线观看| 欧美精品99| 永久域名在线精品| 亚洲欧美韩国| 亚洲破处大片| 久久在线免费观看视频| 国产女优一区| 亚洲一级片在线观看| 欧美成人免费小视频| 欧美在线观看一二区| 国产精品卡一卡二| 99精品视频一区| 欧美黄色视屏| 久久一区二区三区四区五区| 国产欧美一区二区精品秋霞影院| 99国产精品99久久久久久粉嫩| 男男成人高潮片免费网站|