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

隨筆-341  評論-2670  文章-0  trackbacks-0
    復雜的東西寫多了,如今寫點簡單的好了。由于功能上的需要,Vczh Library++3.0被我搞得很離譜。為了開發維護的遍歷、減少粗心犯下的錯誤以及增強單元測試、回歸測試和測試工具,因此記錄下一些開發上的小技巧,以便拋磚引玉,造福他人。歡迎高手來噴,菜鳥膜拜。

    上一篇文章講到了如何檢查內存泄露。其實只要肯用C++的STL里面的高級功能的話,內存泄露是很容易避免的。我在開發Vczh Library++ 3.0的時候,所有的測試用例都保證跑完了沒有內存泄露。但是很可惜有些C++團隊不能使用異常,更甚者不允許寫構造函數析構函數之類,前一個還好,后一個簡直就是在用C。當然有這些變態規定的地方STL都是用不了的,所以我們更加需要扎實的基礎來開發C++程序。

    今天這一篇主要還是講指針的問題。因為上一篇文章一筆帶過,今天就來詳細講內存泄漏或者野指針發生的各種情況。當然我不可能一下子舉出全部的例子,只能說一些常見的。

    一、錯誤覆蓋內存。

    之前提到的不能隨便亂memset其實就是為了避免這個問題的。其實memcpy也不能亂用,我們來看一個例子,最簡單的:
 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 };

    大家對這種結構肯定十分熟悉,畢竟是大學時候經常要寫的作業題……好了,大家很容易看得出來這其實是C語言的經典寫法。我們拿到手之后,一般會先初始化一下,然后賦值。
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的用處是將一段內存的每一個字節都設置成同一個數字。這里是0,因此兩個字符串成員的所有字節都會變成0。因此在memset了Student之后,我們通過正常方法來訪問name和id的時候都會得到空串。而且如果Student里面有指針的話,0指針代表的是沒有指向任何有效對象,因此這個時候對指針指向的對象進行讀寫就會立刻崩潰。對于其他數值,0一般作為初始值也不會有什么問題(double什么的要小心)。這就是我們寫程序的時候使用memset的原因。

    好了,如今社會進步,人民當家做主了,死程們再也不需要受到可惡的C語言剝削了,我們可以使用C++!因此我們借助STL的力量把Student改寫成下面這種帶有C++味道的形式:
1 struct Student
2 {
3   std::string name;
4   std::string id;
5   int chinese;
6   int math;
7   int english;
8 };

    我們仍然需要對Student進行初始化,不然三個分數還是隨機值。但是我們又不想每一次創建的時候都對他們分別進行賦值初始化城0。這個時候你心里可能還是想著memset,這就錯了!在memset的時候,你會把std::string內部的不知道什么東西也給memset掉。假如一個空的std::string里面存放的指針指向的是一個空的字符串而不是用0來代表空的時候,一下子內部的指針就被你刷成0,等下std::string的析構函數就沒辦法delete掉指針了,于是內存泄露就出現了。有些朋友可能不知道上面那句話說的是什么意思,我們現在來模擬一下不能memset的std::string要怎么實現。

    為了讓memset一定出現內存泄露,那么std::string里面的指針必須永遠都指向一個有效的東西。當然我們還需要在字符串進行復制的時候復制指針。我們這里不考慮各種優化技術,用最簡單的方法做一個字符串出來:
 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 };

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

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

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

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

    經過一個等號操作符的調用,舊Student的所有成員就被一個新的初始化過的Student給覆蓋了,就如同我們對一個int變量重新賦值一樣常見。當然因為各種復制經常會出現,因此我們也要跟上面貼出來的string的例子一樣,實現好那4個函數。至此我十分不理解為什么某些團隊不允許使用構造函數,我猜就是為了可以memset,其實是很沒道理的。

    二、異常。

    咋一看內存泄露跟異常好像沒什么關系,但實際上這種情況更容易發生。我們來看一個例子:
 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,不過對于這種例子來說,用goto是最優美的解決辦法了。但是大家可以看出來,我們用的是C++,因為這里有new。如果DoSomething發生了異常怎么辦呢?如果GetXXX發生了異常怎么辦呢?我們這里沒有任何的try-catch,一有異常,函數里克結束,兩行可憐的delete就不會被執行到了,于是內存泄漏發生了

    那我們如何避免這種情況下的內存泄露呢?一些可愛的小盆友可能會想到,既然是因為沒有catch異常才發生的內存泄露,那我們來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;

    你能接受嗎?當然是不能的。問題出在哪里呢?因為C++沒有try-finally。你看這些代碼到處都是雷同的東西,顯然我們需要編譯器幫我們把這些問題搞定。最好的解決方法是什么呢?顯然還是構造函數和析構函數。總之記住,如果想要事情成對發生,那么使用構造函數和析構函數

    第一步,GetXXX顯然只能支持C模式的東西,因此我們要寫一個支持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 }

    借助這個函數我們可以看到,因為有了GetXXX這種C的東西,導致我們多了多少麻煩。不過這總是一勞永逸的,有了GetXXX2和修改之后的DoSomething2之后,我們就可以用更簡單的方法來做了:
1 string a,b;
2 if(GetXXX2(a) && GetXXX2(b))
3 {
4   DoSomething2(a, b);
5 }

    多么簡單易懂。這個代碼在任何地方發生了異常,所有new的東西都會被delete。這就是析構函數的一個好處。一個變量的析構函數在這個變量超出了作用域的時候一定會被調用,無論代碼是怎么走出去的。

    今天就說到這里了。說了這么多還是想讓大家不要小看構造函數和析構函數。那種微不足道的因為一小部分不是瓶頸的性能問題而放棄構造函數和析構函數的做法,終究是要為了修bug而加班的。只要明白并用好了構造函數、析構函數和異常,那么C++的特性也可以跟C一樣清楚明白便于理解,而且寫出來的代碼更好看的。大家期待第三篇哈。
posted on 2010-06-23 10:12 陳梓瀚(vczh) 閱讀(11742) 評論(23)  編輯 收藏 引用 所屬分類: C++實用技巧

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

空指針的二進制表示并不一定是全0 。
浮點數也一樣, 0.0f, 0.0, 0.0lf的二進制表示都不一定是全0。
所以, 即使是C語言, 欲使用memset去將指針初始化為空, 或者將浮點初始化為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 }

這個實現有問題, 當出現自賦值的時候:
String s;
s = s;
this->buffer和s.buffer是同一個指針。
32行delete之后, 已經是dangling pointer。
33行傳遞給strlen, 34行傳遞給strcpy都是錯誤的。


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

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

先new再delete也可以不用判斷自賦值的情況了。
  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-23 17:55 | zuhd
@OwnWaterloo
哥,你總是這么犀利,我給你留言看到沒?  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-23 18:33 | OwnWaterloo
@zuhd
剛發現…… 那一天收到的通知太多, 被我直接全部標記為已讀, 然后忘了……
通常用同名gmail郵箱, qq不怎么用……
  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-23 18:42 | 陳梓瀚(vczh)
@OwnWaterloo
為了迅速說明問題,那個string其實還有很多其他的缺陷的……因為在之后講構造函數和析構函數的一篇上會著重處理這種case。

話說回來,我上一篇提到了,這個系列是默認你使用Visual C++的。  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-23 18:46 | 陳梓瀚(vczh)
@OwnWaterloo
話說回來,因為在C++里面,字面量“0”的確是代表空指針,因此如果空指針的二進制真的不是0的話,我可以認為是編譯器的bug。因為從語法上講,既然void* p=0;是對的,那么void* p=(void*)(int)0;也必須是對的。

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


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

float f = 0;
float f = (float)(int)0;
而通常f的二進制表示并不是全0。
這是因為編譯器是能看到這里的轉型動作, 并加入適當的操作。


但這樣寫就是沒有保證的:
void* p;
memset(&p, 0, sizeof p);
memset函數中已經不知道p的類型, 只能將p當作byte 數組。
就沒有機會為指針類型作適當的調整。


再舉個例子:
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);

因為編譯器知道pc,pa,pb的類型。
所以無論是賦值還是比較, 都會插入適當的操作。

而如果使用memset或者memcmp, 就掛了。


最后, 標準中有句話, 在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.
  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-23 20:40 | 付翔
指出個 小錯誤
#define MAX_STRING 20; 不要分號   回復  更多評論
  
# re: C++實用技巧(二) 2010-06-23 21:49 | 陳梓瀚(vczh)
@OwnWaterloo
話說回來,那什么地方的空指針的二進制不是0?  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-23 21:50 | 陳梓瀚(vczh)
@付翔
嗯嗯,這是個錯誤。  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-23 21:52 | 陳梓瀚(vczh)
@OwnWaterloo
不過這個二進制位不是0的事實更加反映出了構造函數的重要性,memset更加不能隨便來了(當然指的是非Visual C++的情況)  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-23 22:12 | OwnWaterloo
@陳梓瀚(vczh)
http://linuxdude.com/Steve_Sumit/C-faq/q5.17.html
整個第5章都是講null pointer的。
  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-23 22:35 | 陳梓瀚(vczh)
@OwnWaterloo
都是些從現在開始見都沒見過的機器……  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-24 01:18 | 匿名
delete null
確定程序不會拋異常?  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-24 01:46 | 匿名(還是俺)
char* strA=new char[MAX_PATH];
這個也不能保證它一定不會拋異常。
new這個數組的時候,加入new到第M個(M小于MAX_PATH)時候拋出異常,這時候也會有內存泄露咯  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-24 03:28 | 陳梓瀚(vczh)
@匿名(還是俺)
如果new一個東西還是敗了,那程序就直接log了崩潰了吧  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-24 10:25 | paul_simon
1 string s;
2 memset(&s, 0, sizeof(s));
//這里有個問題想和博主探討,下文中提到的buffer是String的一個private成
//員,memset函數是不是該在String的成員函數里面調用,比如:
String::mems()
{
memset(buffer,0,sizeof(buffer));
}
//或者可否考慮在String::String()里加入memset函數
//QQ:29975723,謝謝  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-24 21:00 | 陳梓瀚(vczh)
@paul_simon
String當然要為自己負責了,如果String自己覺得memset合適,那當然可以。不過你那么搞有問題,除非buffer是一個數組而不是指針。

但是外部不能memset掉string。  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-25 01:07 | paul_simon
@陳梓瀚(vczh)
String的構造函數決定了buffer是個數組,這里的String和student是兩個不同的對象,String里的buffer成員不能被外部的memset所清零吧?
所以我說的是
1 string s;
2 memset(&s, 0, sizeof(s));//這里的實質不是是對buffer進行清零嗎?  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-25 05:43 | 陳梓瀚(vczh)
@paul_simon
不是,因為類的私有部分是不透明的,所以你在外部操作的時候,不能以知道string的實現作為前提,人家改了怎么辦,你就要加班了。  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-28 02:11 | 球球
如果memset用在子類的初始化時...  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-28 03:22 | 陳梓瀚(vczh)
@球球
子類也不能假設父類是如何實現的。  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-29 00:06 | chenq
用那么多代碼去try catch那個GetXXX,為什么不直接用smart pointer呢  回復  更多評論
  
# re: C++實用技巧(二) 2010-06-29 09:58 | 陳梓瀚(vczh)
@chenq
因為用了smart pointer就不能告訴人們C風格的丑陋  回復  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            午夜精品一区二区三区在线 | 一色屋精品视频免费看| 午夜精品美女自拍福到在线| 久久天堂av综合合色| 一本久久综合亚洲鲁鲁五月天| 妖精成人www高清在线观看| 国产精品久久福利| 蜜臀久久99精品久久久画质超高清 | 性久久久久久久久久久久| 翔田千里一区二区| 美女诱惑黄网站一区| 欧美精品在线观看播放| 久久视频在线看| 亚洲主播在线播放| 中文欧美在线视频| 亚洲精品欧美在线| 亚洲国产精品123| 久久青草欧美一区二区三区| 欧美在线视屏 | 看欧美日韩国产| 新狼窝色av性久久久久久| 久久久精彩视频| 久久精品五月婷婷| 欧美日韩精品免费观看视频| 久久综合九色欧美综合狠狠| 欧美另类视频| 精品999日本| 国内精品写真在线观看| 国产噜噜噜噜噜久久久久久久久 | 久久久久久久波多野高潮日日| 亚洲午夜精品网| 亚洲人成在线观看一区二区| 欧美国产日韩亚洲一区| 久久在线免费观看| 99re国产精品| 亚洲欧美日韩另类| 欧美精品在线视频| 在线看片欧美| 亚洲国产一区二区三区在线播| 在线播放国产一区中文字幕剧情欧美| 亚洲作爱视频| 亚洲国产成人av好男人在线观看| 亚洲欧美综合国产精品一区| 欧美精品一区二区三| 亚洲第一视频网站| 久久久久一区二区三区| 蜜桃伊人久久| 亚洲电影中文字幕| 久久超碰97中文字幕| 久久九九热re6这里有精品| 国产精品久久久久久久7电影| 日韩午夜电影| 欧美伦理一区二区| 久久精品国产999大香线蕉| 国产精品久久久久久久久久久久久| 亚洲日韩中文字幕在线播放| 亚洲深夜av| 久久av资源网站| 欧美激情一区二区三区成人| 久久久www成人免费毛片麻豆| 国产亚洲精品7777| 99国产精品久久| 亚洲丶国产丶欧美一区二区三区| 久久久久久久综合狠狠综合| 一区二区三区中文在线观看| 巨胸喷奶水www久久久免费动漫| 亚洲欧洲精品一区二区三区波多野1战4 | 亚洲男女自偷自拍| 欧美中文字幕不卡| 亚洲午夜国产成人av电影男同| 欧美日韩中文精品| 在线播放豆国产99亚洲| 久久亚洲综合网| 久久久噜噜噜久久狠狠50岁| 亚洲国产视频a| 亚洲人成在线观看网站高清| 国产精品高潮呻吟久久| 久久精品国产精品 | 亚洲激情av| 亚洲日本成人网| 国产精品少妇自拍| 99精品免费| 亚洲视频精选在线| 国产一区 二区 三区一级| 久久躁日日躁aaaaxxxx| 免费亚洲视频| 激情成人中文字幕| 亚洲国产日韩欧美在线动漫| 国产精品xxxav免费视频| 日韩小视频在线观看| 一区二区三区精品久久久| 国产午夜精品在线| 午夜欧美理论片| 久久久久久久久久久一区 | 国产精品久久久久久久久久久久久| 欧美在线观看一区二区| av成人福利| 欧美乱妇高清无乱码| 欧美一区二区三区视频| 麻豆精品视频| 欧美一区二区三区视频免费| 欧美成人蜜桃| 亚洲免费观看高清完整版在线观看| 久久看片网站| 欧美日韩第一区| 亚洲欧美日韩天堂一区二区| 欧美区一区二| 夜夜爽99久久国产综合精品女不卡| 亚洲制服丝袜在线| 国产在线精品一区二区夜色| 美女精品自拍一二三四| 欧美日韩伦理在线免费| 一本色道久久综合亚洲91| 亚洲一区精彩视频| 国产精品日本精品| 欧美不卡一区| 欧美成人精品不卡视频在线观看 | 香蕉久久夜色精品| 亚洲视频福利| 一本色道久久综合亚洲二区三区| 久久精品国产99| 欧美一区二区视频在线观看2020| 欧美日韩国产va另类| 亚洲国产日本| 亚洲激情影视| 欧美91福利在线观看| 欧美成人午夜| 欧美四级在线观看| 亚洲成色777777女色窝| 欧美日韩免费观看一区=区三区| 免费av成人在线| 狠狠色狠狠色综合日日五| 亚洲人成7777| 亚洲黄页一区| 美女主播一区| 欧美激情一区二区三区成人| 亚洲大黄网站| 狼人社综合社区| 亚洲黄色一区| 在线一区二区视频| 久久久久久夜精品精品免费| 久久精品欧美日韩| 国产一区二区三区久久 | 一区二区三区在线不卡| 欧美一区观看| 日韩一级黄色av| 欧美日韩国产综合视频在线观看| 91久久精品视频| 亚洲伊人一本大道中文字幕| 国产精品乱码久久久久久| 欧美成人亚洲成人| 亚洲精选视频在线| 欧美日韩一区二区在线播放| 亚洲无限av看| 久久影视精品| 日韩一二在线观看| 国产精品丝袜久久久久久app | 欧美日韩在线播放一区| 亚洲深夜影院| 久久高清国产| 亚洲精品久久久久中文字幕欢迎你 | 欧美喷水视频| 老司机免费视频一区二区| 亚洲国产精品久久久久秋霞影院| 亚洲欧洲另类国产综合| 一区二区精品| 国模大胆一区二区三区| 免费国产自线拍一欧美视频| 一本久道综合久久精品| 久久亚洲春色中文字幕久久久| 亚洲国产精品国自产拍av秋霞| 欧美日韩久久精品| 久久久久久**毛片大全| 99精品久久久| 久久午夜av| 亚洲在线黄色| 亚洲精品日韩久久| 国产主播精品| 欧美日韩在线另类| 久久久久九九九九| 亚洲视频在线观看网站| 欧美国产三级| 久久精品日韩欧美| 亚洲桃花岛网站| 亚洲激情在线观看视频免费| 国产区亚洲区欧美区| 午夜免费日韩视频| 亚洲第一成人在线| 久久成人18免费观看| 亚洲视频欧美在线| 亚洲国产欧美在线人成| 国产亚洲人成网站在线观看| 欧美视频手机在线| 欧美福利视频在线| 99视频精品全国免费| 欧美不卡高清| 久久婷婷国产麻豆91天堂| 午夜在线精品| 午夜精品成人在线| 亚洲欧美亚洲|