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

Just enjoy programming

#

skiplist

    最近開始看leveldb的代碼,周末看了下skiplist,詳細(xì)介紹可以看http://blog.xiaoheshang.info/?p=248。基本原理就是空間換效率,多用幾個(gè)指針來(lái)?yè)Q取查找插入效率。自己也嘗試寫了下,對(duì)比了下leveldb的代碼,內(nèi)存控制沒有l(wèi)eveldb實(shí)現(xiàn)的好,leveldb申請(qǐng)的時(shí)候基本上都是以block為單位申請(qǐng)空間,這樣可以減少內(nèi)存碎片,空間上每個(gè)節(jié)點(diǎn)就只會(huì)申請(qǐng)指定level個(gè)數(shù)的指針。以前一直記混淆 const char *p , char const *p 和char * const p的區(qū)別,前兩者代碼指向的內(nèi)容不可變,后者指向的指針不可變。

posted @ 2014-05-11 23:03 周強(qiáng) 閱讀(401) | 評(píng)論 (0)編輯 收藏

2013

      時(shí)間好快,不知不覺就步入了2014年,回顧2013,有收獲也有遺憾,最大的收獲就是遇到了“她”,真的感謝“她”在我還一無(wú)所有的時(shí)候選擇了我,雖然現(xiàn)在的我還不夠優(yōu)秀,但今后的日子我會(huì)盡自己最大的努力讓你幸福。每每打電話回家的時(shí)候總有點(diǎn)愧疚感,父母這么大年紀(jì)還在起早摸黑的干活,希望能早日讓他們停下來(lái)安詳晚年。2013遺憾的是技術(shù)積累不夠,總感覺自己很忙,但卻成長(zhǎng)較慢,很多時(shí)候自己都認(rèn)為存在的都是合理的,沒有多思考下為什么這樣設(shè)計(jì),會(huì)不會(huì)有更好的設(shè)計(jì)實(shí)現(xiàn)。2014希望自己能在技術(shù)上有所積累,希望自己能靜下心來(lái)專注做好該做的事情,不能太著急,慢慢積累,或許10年能專注地做好一件事也已經(jīng)很不錯(cuò)了。

posted @ 2014-01-03 21:17 周強(qiáng) 閱讀(197) | 評(píng)論 (0)編輯 收藏

python functools wraps (轉(zhuǎn))

When you use a decorator, you're replacing one function with another. In other words, if you have a decorator

  1. def logged(func):  
  2.     def with_logging(*args, **kwargs):  
  3.         print func.__name__ + " was called"  
  4.         return func(*args, **kwargs)  
  5.     return with_logging  

then when you say

  1. @logged  
  2. def f(x):  
  3.    """does some math"""  
  4.    return x + x * x  

it's exactly the same as saying

  1. def f(x):  
  2.     """does some math"""  
  3.     return x + x * x  
  4. f = logged(f)  

and your function f is replaced with the function with_logging. Unfortunately, this means that if you then say

  1. print f.__name__  

it will print with_logging because that's the name of your new function. In fact, if you look at the docstring for f, it will be blank because with_logging has no docstring, and so the docstring you wrote won't be there anymore. Also, if you look at the pydoc result for that function, it won't be listed as taking one argument x; instead it'll be listed as taking *args and **kwargs because that's what with_logging takes.

If using a decorator always meant losing this information about a function, it would be a serious problem. That's why we have functools.wraps. This takes a function used in a decorator and adds the functionality of copying over the function name, docstring, arguments list, etc. And since wraps is itself a decorator, the following code does the correct thing:

  1. from functools import wraps  
  2. def logged(func):  
  3.     @wraps(func)  
  4.     def with_logging(*args, **kwargs):  
  5.         print func.__name__ + " was called"  
  6.         return func(*args, **kwargs)  
  7.     return with_logging  
  8.  
  9. @logged  
  10. def f(x):  
  11.    """does some math"""  
  12.    return x + x * x  
  13.   
  14. print f.__name__  # prints 'f'  
  15. print f.__doc__   # prints 'does some math'  


    轉(zhuǎn)自http://blog.csdn.net/wanghai__/article/details/7078792

posted @ 2013-11-05 20:40 周強(qiáng) 閱讀(392) | 評(píng)論 (0)編輯 收藏

Oracle Redo Log 機(jī)制 小結(jié)(轉(zhuǎn)載)

     摘要: Oracle 的Redo 機(jī)制DB的一個(gè)重要機(jī)制,理解這個(gè)機(jī)制對(duì)DBA來(lái)說也是非常重要,之前的Blog里也林林散散的寫了一些,前些日子看老白日記里也有說明,所以結(jié)合老白日記里的內(nèi)容,對(duì)oracle 的整個(gè)Redo log 機(jī)制重新整理一下。 一.Redo log 說明Oracle 的Online redo log 是為確保已經(jīng)提交的事務(wù)不會(huì)丟失而建立的一個(gè)機(jī)制。 因?yàn)檫@種健全的機(jī)制,才能...  閱讀全文

posted @ 2013-01-08 19:20 周強(qiáng) 閱讀(4923) | 評(píng)論 (0)編輯 收藏

【操作系統(tǒng)】Linux性能監(jiān)控——CPU、Memory、IO、Network(轉(zhuǎn)載)

     摘要: 【操作系統(tǒng)】Linux性能監(jiān)控——CPU、Memory、IO、Networkby illidan(綜合了幾篇文章和自己的實(shí)踐) 一、CPU1、良好狀態(tài)指標(biāo)CPU利用率:User Time <= 70%,System Time <= 35%,User Time + System Time <= 70%。上下文切換:與CPU利用率相關(guān)聯(lián),如果CPU利...  閱讀全文

posted @ 2012-12-26 22:02 周強(qiáng) 閱讀(1389) | 評(píng)論 (0)編輯 收藏

top命令(轉(zhuǎn)載)

     摘要: TOP是一個(gè)動(dòng)態(tài)顯示過程,即可以通過用戶按鍵來(lái)不斷刷新當(dāng)前狀態(tài).如果在前臺(tái)執(zhí)行該命令,它將獨(dú)占前臺(tái),直到用戶終止該程序?yàn)橹?比較準(zhǔn)確的說,top命令提供了實(shí)時(shí)的對(duì)系統(tǒng)處理器的狀態(tài)監(jiān)視.它將顯示系統(tǒng)中CPU最“敏感”的任務(wù)列表.該命令可以按CPU使用.內(nèi)存使用和執(zhí)行時(shí)間對(duì)任務(wù)進(jìn)行排序;而且該命令的很多特性都可以通過交互式命令或者在個(gè)人定制文件中進(jìn)行設(shè)定.top - 12:38...  閱讀全文

posted @ 2012-08-28 20:42 周強(qiáng) 閱讀(396) | 評(píng)論 (0)編輯 收藏

技巧:多共享動(dòng)態(tài)庫(kù)中同名對(duì)象重復(fù)析構(gòu)問題的解決方法(轉(zhuǎn)載)

Linux 支持的共享程序庫(kù)(lib*.so)技術(shù)不僅能夠有效利用系統(tǒng)資源,而且還對(duì)程序設(shè)計(jì)帶來(lái)了很大的便利性、通用性等,因此被各種級(jí)別的應(yīng)用系統(tǒng)廣泛采用。 動(dòng)態(tài)鏈接的共享庫(kù)是在加載應(yīng)用程序時(shí)被加載的,而且它與應(yīng)用程序是在運(yùn)行時(shí)綁定的:通過動(dòng)態(tài)鏈接器,將動(dòng)態(tài)共享庫(kù)映射進(jìn)應(yīng)用程序的可執(zhí)行內(nèi)存中(動(dòng)態(tài)鏈接);在啟動(dòng)應(yīng)用程序時(shí),動(dòng)態(tài)裝載器將所需的共享目標(biāo)庫(kù)映射到應(yīng)用程序的內(nèi)存(動(dòng)態(tài)裝載)。

在通常情況下,共享庫(kù)都是通過使用附加選項(xiàng) -fpic 或 -fPIC 進(jìn)行編譯,從目標(biāo)代碼產(chǎn)生位置無(wú)關(guān)的代碼(Position Independent Code,PIC),使用 -shared選項(xiàng)將目標(biāo)代碼放進(jìn)共享目標(biāo)庫(kù)中。位置無(wú)關(guān)代碼需要能夠被加載到不同進(jìn)程的不同地址,并且能得以正確的執(zhí)行,故其代碼要經(jīng)過特別的編譯處理:位置無(wú)關(guān)代碼(PIC)對(duì)常量和函數(shù)入口地址的操作都是采用基于基寄存器(base register)BASE+ 偏移量的相對(duì)地址的尋址方式。即使程序被裝載到內(nèi)存中的不同地址,即 BASE 值不同,而偏移量是不變的,所以程序仍然可以找到正確的入口地址或者常量。

然而,當(dāng)應(yīng)用程序鏈接了多個(gè)共享庫(kù),如果在這些共享庫(kù)中,存在相同作用域范圍的同名靜態(tài)成員變量或者同名 ( 非靜態(tài) ) 全局變量,那么當(dāng)程序訪問完靜態(tài)成員變量或全局變量結(jié)束析構(gòu)時(shí),由于某內(nèi)存塊的 double free 會(huì)導(dǎo)致 core dump,這是由于 Linux 編譯器的缺陷造成的。

應(yīng)用場(chǎng)景原型

該問題源于筆者所從事的開發(fā)項(xiàng)目:IBM Tivoli Workload Scheduler (TWS) LoadLevelerLoadLeveler是 IBM在高性能計(jì)算(High Performance Computing,HPC)領(lǐng)域的一款作業(yè)調(diào)度軟件。它主要分為兩個(gè)大的模塊,分別是調(diào)度模塊(scheduler)和資源管理模塊(resource manger)。 兩個(gè)模塊中分別含有關(guān)于配置管理功能的共享庫(kù),由于某些配置管理選項(xiàng)為兩模塊所共同采用,所以兩模塊之間共享了部分源文件代碼,其中包含有同名的類靜態(tài)成員。

可以通過以下簡(jiǎn)單的模型進(jìn)行描述:


圖 1. 應(yīng)用場(chǎng)景
圖片示例 

對(duì)應(yīng)的各模塊代碼片段如下圖所示:


圖 2. 應(yīng)用場(chǎng)景模擬代碼
圖片示例 

其中,test.c 是主程序,包含有兩個(gè)頭文件:api1.h 與 api2.h;頭文件 api1.h 包含頭文件 lib1/lib.h 和一功能函數(shù) func_api1(),api2.h 包含頭文件 lib2/lib.h 和一功能函數(shù) func_api2();目錄 lib1 和 lib2 下的源文件分別編譯生成共享庫(kù) lib1.so 和 lib2.so。同時(shí),頭文件 lib1/lib.h 與 lib2/lib.h 鏈接到同一共享文件 lib.h。在文件 lib.h 中定義有一靜態(tài)成員變量“static std::vector<int> vec_int”。

回頁(yè)首

功能函數(shù)與各靜態(tài)成員函數(shù)代碼清單

功能函數(shù) func_api1() 與 func_api2() 的實(shí)現(xiàn)類似,通過調(diào)用靜態(tài)成員函數(shù)達(dá)到訪問靜態(tài)成員變量 vec_int的目的:


清單 1. 功能函數(shù) func_api1(int)
          void func_api1(int i) {      printf("%s.\n", __FILE__);       A::set(i);      A::print();      return;   }      

靜態(tài)成員函數(shù) A::set() 與 A::print() 的實(shí)現(xiàn)如下:


清單 2. 靜態(tài)成員函數(shù) A::set(int)
          void A::set(int num) {      vec_int.clear();      for (int i = 0; i < num; i++) {          vec_int.push_back(i);      }      return;   }      


清單 3. 靜態(tài)成員函數(shù) A::print()
          void A::print() {      for (int i = 0; i < vec_int.size(); i++) {          printf("vec_int[%d] = %d, addr: %p.\n", i, vec_int[i], &vec_int[i]);      }      printf("vec_int addr: %p.\n", &vec_int);      return;   }      

A::set() 對(duì)靜態(tài)成員 vec_int進(jìn)行賦值操作,而 A::print() 則打印其中的值與當(dāng)前項(xiàng)的內(nèi)存地址。

回頁(yè)首

運(yùn)行結(jié)果

如果兩個(gè)共享庫(kù)是通過選項(xiàng) -fpic或 -fPIC編譯的話,運(yùn)行程序 test,輸出如下:


清單 4. 選項(xiàng) -fPIC 的測(cè)試結(jié)果
          $ export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH   $ g++ -g -o lib1.so -fPIC-rdynamic -shared lib1/lib.c   $ g++ -g -o lib2.so -fPIC-rdynamic -shared lib2/lib.c   $ g++ -g -o test -L./ -l1 -l2 test.c   $ ./test  api1.h.   vec_int[0] = 0, addr: 0x9cbf028.   vec_int[1] = 1, addr: 0x9cbf02c.   vec_int[2] = 2, addr: 0x9cbf030.   vec_int[3] = 3, addr: 0x9cbf034.   vec_int addr: 0xe89228.   *** glibc detected *** ./test: double free or corruption (fasttop): 0x09cbf028***   ======= Backtrace:=========   /lib/libc.so.6[0x2b2b16]   /lib/libc.so.6(cfree+0x90)[0x2b6030]   /usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0x5d1731]   ./lib1.so(_ZN9__gnu_cxx13new_allocatorIiE10deallocateEPij+0x1d)[0xe88417]         ./lib1.so(_ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPij+0x33)[0xe88451]         ./lib1.so(_ZNSt12_Vector_baseIiSaIiEED2Ev+0x42)[0xe8849a]         ./lib1.so(_ZNSt6vectorIiSaIiEED1Ev+0x60)[0xe8850c]  ./lib2.so[0x961d6c]   /lib/libc.so.6(__cxa_finalize+0xa9)[0x275c79]   ./lib2.so[0x961c34]   ./lib2.so[0x962d3c]   /lib/ld-linux.so.2[0x23a7de]   /lib/libc.so.6(exit+0xe9)[0x2759c9]   /lib/libc.so.6(__libc_start_main+0xe4)[0x25fdf4]   ./test(__gxx_personality_v0+0x45)[0x80484c1]   ======= Memory map:========   ......   00960000-00963000 r-xp 00000000 00:1b 7668734    ./lib2.so   00963000-00964000 rwxp 00003000 00:1b 7668734    ./lib2.so   00970000-00971000 r-xp 00970000 00:00 0          [vdso]   00e86000-00e89000 r-xp 00000000 00:1b 7668022    ./lib1.so   00e89000-00e8a000 rwxp 00003000 00:1b 7668022    ./lib1.so  08048000-08049000 r-xp 00000000 00:1b 7668748    ./test   08049000-0804a000 rw-p 00000000 00:1b 7668748    ./test   09cbf000-09ce0000 rw-p 09cbf000 00:00 0          [heap]  ......   Abort(coredump)   $      

從程序的輸出直觀的看到,core 產(chǎn)生是由于堆內(nèi)存區(qū)域(09cbf000-09ce0000)中起始地址為 0x09cbf028的內(nèi)存區(qū)被釋放了兩次導(dǎo)致的,該地址正式靜態(tài)成員變量 vec_int的第一個(gè)元素的地址。

為什么會(huì)出現(xiàn)同一塊內(nèi)存區(qū),被釋放兩次的情形呢?

回頁(yè)首

原因分析

我們知道,靜態(tài)成員變量與全局變量類似,都采用了靜態(tài)存儲(chǔ)方式。對(duì)于加了選項(xiàng) -fpic或 -fPIC的共享庫(kù),這些變量的地址都存放在該共享庫(kù)的全局偏移表(Global Offset Table,GOT)中。

通過 objdump或者 readelf命令分析共享庫(kù) lib1.so,結(jié)果如下:


清單 5. objdump 分析共享庫(kù) lib1.so 的輸出
          $ objdump -x -R lib1.so    lib1.so:     file format elf32-i386   ......   Sections:   Idx Name          Size      VMA       LMA       File off  Algn    0 .gnu.hash     000001e8  000000d4  000000d4  000000d4  2**2                    CONTENTS, ALLOC, LOAD, READONLY, DATA   ......   18 .dynamic      000000d8  0000301c  0000301c  0000301c  2**2                    CONTENTS, ALLOC, LOAD, DATA   19 .got          00000014  000030f4  000030f4  000030f4  2**2                   CONTENTS, ALLOC, LOAD, DATA   20 .got.plt      00000114  00003108  00003108  00003108  2**2                    CONTENTS, ALLOC, LOAD, DATA   ......   DYNAMIC RELOCATION RECORDS   OFFSET   TYPE              VALUE   ......   000030f4 R_386_GLOB_DAT    __gmon_start__   000030f8 R_386_GLOB_DAT    _Jv_RegisterClasses   000030fc R_386_GLOB_DAT    _ZN1A7vec_intE  00003104 R_386_GLOB_DAT    __cxa_finalize   ......      


清單 6. readelf 分析共享庫(kù) lib1.so 的輸出
          $ objdump -x -R lib1.so    lib1.so:     file format elf32-i386   ......   Sections:   Idx Name          Size      VMA       LMA       File off  Algn    0 .gnu.hash     000001e8  000000d4  000000d4  000000d4  2**2                    CONTENTS, ALLOC, LOAD, READONLY, DATA   ......   18 .dynamic      000000d8  0000301c  0000301c  0000301c  2**2                    CONTENTS, ALLOC, LOAD, DATA   19 .got          00000014  000030f4  000030f4  000030f4  2**2                   CONTENTS, ALLOC, LOAD, DATA   20 .got.plt      00000114  00003108  00003108  00003108  2**2                    CONTENTS, ALLOC, LOAD, DATA   ......   DYNAMIC RELOCATION RECORDS   OFFSET   TYPE              VALUE   ......   000030f4 R_386_GLOB_DAT    __gmon_start__   000030f8 R_386_GLOB_DAT    _Jv_RegisterClasses   000030fc R_386_GLOB_DAT    _ZN1A7vec_intE  00003104 R_386_GLOB_DAT    __cxa_finalize   ......      

從上面兩個(gè)命令的輸出結(jié)果中可以看出,共享庫(kù) lib1.so中 GOT段的起始內(nèi)存地址為 000030f4,大小為 20 字節(jié) (0x14);靜態(tài)成員變量 vec_int在共享庫(kù) lib1.so中的起始偏移地址為 000030fc。顯然,vec_int位于該共享庫(kù)的 GOT段內(nèi)。

當(dāng)應(yīng)用程序同時(shí)鏈接 lib1.so和 lib2.so時(shí),同名靜態(tài)成員變量 vec_int分別位于其共享庫(kù)的 GOT區(qū)。當(dāng)程序運(yùn)行時(shí),系統(tǒng)從符號(hào)表中查找并裝載構(gòu)造一份 vec_int數(shù)據(jù),這點(diǎn)從程序運(yùn)行的輸出結(jié)果(清單 4)的“Backtrace”部分可以看到:只有 lib1.so中的靜態(tài)成員變量被裝載構(gòu)造;同時(shí),通過內(nèi)存映射(Memory map)部分(清單 4),可以觀察到 vec_int對(duì)象的地址 0xe89228正好處在為共享庫(kù) lib1.so分配的可讀內(nèi)存區(qū) 00e89000-00e8a000中:

        00e89000-00e8a000 rwxp 00003000 00:1b 7668022    ./lib1.so

然后,當(dāng)程序結(jié)束時(shí),卻對(duì)該變量進(jìn)行了兩次析構(gòu)操作,通過 gdb分析 core 文件:


清單 7. core 文件分析結(jié)果
          $ gdb ./test core.28440 ……  Core was generated by `./test'.   Program terminated with signal 6, Aborted.   #0  0x00970402 in __kernel_vsyscall ()   (gdb)   (gdb) where   #0  0x00970402 in __kernel_vsyscall ()   #1  0x00272d10 in raise () from /lib/libc.so.6   #2  0x00274621 in abort () from /lib/libc.so.6   #3  0x002aae5b in __libc_message () from /lib/libc.so.6   #4  0x002b2b16 in _int_free () from /lib/libc.so.6   #5  0x002b6030 in free () from /lib/libc.so.6   #6  0x005d1731 in operator delete () from /usr/lib/libstdc++.so.6   #7  0x00e88417 in __gnu_cxx::new_allocator<int>::deallocate       (this=0xe89228, __p=0x9cbf028)      at /usr/lib/gcc/i386-redhat-linux/.../ext/new_allocator.h:94   #8  0x00e88451 in std::_Vector_base<int, ... (this=0xe89228, __p=0x9cbf028, __n=4)      at /usr/lib/gcc/.../include/c++/4.1.2/bits/stl_vector.h:133   #9  0x00e8849a in ~_Vector_base (this=0xe89228)      at /usr/lib/gcc/.../include/c++/4.1.2/bits/stl_vector.h:119   #10 0x00e8850cin ~vector (this=0xe89228) at /usr/lib/gcc/.../stl_vector.h:272   #11 0x00961d6c in __tcf_0 () at lib2/lib.c:3   #12 0x00275c79 in __cxa_finalize () from /lib/libc.so.6   #13 0x00961c34 in __do_global_dtors_aux () from ./lib2.so   #14 0x00962d3c in _fini () from ./lib2.so  #15 0x0023a7de in _dl_fini () from /lib/ld-linux.so.2   #16 0x002759c9 in exit () from /lib/libc.so.6   #17 0x0025fdf4 in __libc_start_main () from /lib/libc.so.6   #18 0x080484c1 in _start ()   (gdb)      

從清單 7 中可以看出,從幀 #14 開始,程序進(jìn)行 lib2.so中的析構(gòu)操作,直到 #11,都運(yùn)行在 lib2.so中,當(dāng)進(jìn)入幀 #10 時(shí),進(jìn)行變量析構(gòu)時(shí),其地址為 0x00e8850c,該地址中的對(duì)象是程序啟動(dòng)時(shí)由共享庫(kù) lib1.so裝載構(gòu)造出來(lái)的(清單 1):

        ./lib1.so(_ZNSt6vectorIiSaIiEED1Ev+0x60)[0xe8850c]

當(dāng)程序結(jié)束時(shí),運(yùn)行庫(kù) glibc檢測(cè)到共享庫(kù) lib2.so析構(gòu)了并非由其構(gòu)造的對(duì)象,導(dǎo)致了 core dump。

這種情況下,如果替換使用選項(xiàng) -fpie或 -fPIE,操作步驟與運(yùn)行結(jié)果如下所示:


清單 8. 選項(xiàng) -fPIE 的測(cè)試結(jié)果
          $ export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH   $ g++ -g -o lib1.so -fPIE-rdynamic -shared lib1/lib.c   $ g++ -g -o lib2.so -fPIE-rdynamic -shared lib2/lib.c   $ g++ -g -pie -o test -L./ -l1 -l2 test.c   $ ./test  api1.h.   vec_int[0] = 0, addr: 0x80e3028.   vec_int[1] = 1, addr: 0x80e302c.   vec_int[2] = 2, addr: 0x80e3030.   vec_int[3] = 3, addr: 0x80e3034.   vec_int addr: 0x75e224.   $      

程序運(yùn)行結(jié)果符合期望并正常結(jié)束。

這是因?yàn)椋?dāng)使用選項(xiàng) -fpie或 -fPIE時(shí),生成的共享庫(kù)不會(huì)為靜態(tài)成員變量或全局變量在 GOT中創(chuàng)建對(duì)應(yīng)的條目(通過 objdumpreadelf命令可以查看,此處不再贅述),從而避免了由于靜態(tài)對(duì)象“構(gòu)造一次,析構(gòu)兩次”而對(duì)同一內(nèi)存區(qū)域釋放兩次引起的程序 core dump。

選項(xiàng) -fpie和 -fPIE與 -fpic及 -fPIC的用法很相似,區(qū)別在于前者總是將生成的位置無(wú)關(guān)代碼看作是屬于程序本身,并直接鏈接進(jìn)該可執(zhí)行程序,而非存入全局偏移表 GOT中;這樣,對(duì)于同名的靜態(tài)或全局對(duì)象的訪問,其構(gòu)造與析構(gòu)操作將保持一一對(duì)應(yīng)。

回頁(yè)首

結(jié)束語(yǔ)

通過使用選項(xiàng) -fpie或 -fPIE代替 -fpic或者 -fPIC,使得生成的共享庫(kù)不會(huì)為靜態(tài)成員變量或全局變量在 GOT中創(chuàng)建對(duì)應(yīng)的條目,同時(shí)也就避免了針對(duì)同名靜態(tài)對(duì)象“構(gòu)造一次,析構(gòu)兩次”的不當(dāng)操作。

轉(zhuǎn)自:http://www.ibm.com/developerworks/cn/linux/l-cn-sdlstatic/ 





posted @ 2012-03-02 16:04 周強(qiáng) 閱讀(455) | 評(píng)論 (0)編輯 收藏

CppUnit快速入門(轉(zhuǎn)載)

簡(jiǎn)介

測(cè)試是軟件開發(fā)過程中極其重要的一環(huán),詳盡周密的測(cè)試能夠減少軟件BUG,提高軟件品質(zhì)。測(cè)試包括單元測(cè)試、系統(tǒng)測(cè)試等。其中單元測(cè)試是指針對(duì)軟件功能單元所作的測(cè)試,這里的功能單元可以是一個(gè)類的屬性或者方法,測(cè)試的目的是看這些基本單元是否工作正常。由于單元測(cè)試的內(nèi)容很基礎(chǔ),因此可以看作是測(cè)試工作的第一環(huán),該項(xiàng)工作一般由開發(fā)人員自行完成。如果條件允許,單元測(cè)試代碼的開發(fā)應(yīng)與程序代碼的開發(fā)同步進(jìn)行。

雖然不同程序的單元測(cè)試代碼不盡相同,但測(cè)試代碼的框架卻非常相似,于是便出現(xiàn)了一些單元測(cè)試類庫(kù),CppUnit便是其中之一。

CppUnit是XUnit中的一員,XUnit是一個(gè)大家族,還包括JUnit和PythonUnit等。CppUnit簡(jiǎn)單實(shí)用,學(xué)習(xí)和使用起來(lái)都很方便,網(wǎng)上已有一些文章對(duì)其作介紹,但本文更著重于講解其中的基本概念和使用方法,以幫助初次接觸CppUnit的人員快速入門。

安裝

目前,CppUnit的最新版本是1.10.2,你可以從下面地址獲取:

http://sourceforge.net/projects/cppunit

解壓后,你可以看到CppUnit包含如下目錄:

config: 配置文件 contrib: contribution,其他人貢獻(xiàn)的外圍代碼 doc: 文檔,需要通過doxygen工具生成,也可以直接從sourceforge站點(diǎn)上下載打包好的文檔 examples:示例代碼 include: 頭文件 lib: 存放編譯好的庫(kù) src: 源文件,以及編譯庫(kù)的工程等

然后打開src目錄下的CppUnitLibraries工程,執(zhí)行build/batch build,編譯成功的話,生成的庫(kù)文件將被拷貝到lib目錄下。

你也可以根據(jù)需要選擇所需的項(xiàng)目進(jìn)行編譯,其中項(xiàng)目cppunit為靜態(tài)庫(kù),cppunit_dll為動(dòng)態(tài)庫(kù),生成的庫(kù)文件為:

cppunit.lib: 靜態(tài)庫(kù)release版 cppunitd.lib: 靜態(tài)庫(kù)debug版 cppunit_dll.lib: 動(dòng)態(tài)庫(kù)release版 cppunitd_dll.lib:動(dòng)態(tài)庫(kù)debug版

要使用CppUnit,還得設(shè)置好頭文件和庫(kù)文件路徑,以VC6為例,選擇Tools/Options/Directories,在Include files和Library files中分別添加%CppUnitPath%/include和%CppUnitPath%/lib,其中%CppUnitPath%表示CppUnit所在路徑。

做好準(zhǔn)備工作后,我們就可以編寫自己的單元測(cè)試代碼了。需說明的是,CppUnit所用的動(dòng)態(tài)運(yùn)行期庫(kù)均為多線程動(dòng)態(tài)庫(kù),因此你的單元測(cè)試程序也得使用相應(yīng)設(shè)置,否則會(huì)發(fā)生沖突。

概念

在使用之前,我們有必要認(rèn)識(shí)一下CppUnit中的主要類,當(dāng)然你也可以先看后面的例子,遇到問題再回過頭來(lái)看這一節(jié)。

CppUnit核心內(nèi)容主要包括六個(gè)方面,

1. 測(cè)試對(duì)象(Test,TestFixture,...):用于開發(fā)測(cè)試用例,以及對(duì)測(cè)試用例進(jìn)行組織管理。

2. 測(cè)試結(jié)果(TestResult):處理測(cè)試用例執(zhí)行結(jié)果。TestResult與下面的TestListener采用的是觀察者模式(Observer Pattern)。

3. 測(cè)試結(jié)果監(jiān)聽者(TestListener):TestListener作為TestResult的觀察者,擔(dān)任實(shí)際的結(jié)果處理角色。

4. 結(jié)果輸出(Outputter):將結(jié)果進(jìn)行輸出,可以制定不同的輸出格式。

5. 對(duì)象工廠(TestFactory):用于創(chuàng)建測(cè)試對(duì)象,對(duì)測(cè)試用例進(jìn)行自動(dòng)化管理。

6. 測(cè)試執(zhí)行體(TestRunner):用于運(yùn)行一個(gè)測(cè)試。

以上各模塊的主要類繼承結(jié)構(gòu)如下:

Test TestFixture TestResult TestListener _______|_________ | | | | | TestSuccessListener TestComposite TestLeaf | | | |____________| TestResultCollector TestSuit | TestCase | TestCaller<Fixture> Outputter TestFactory TestRunner ____________________|_________________ | | | | TestFactoryRegistry CompilerOutputter TextOutputter XmlOutputter | TestSuiteFactory<TestCaseType>

接下來(lái)再對(duì)其中一些關(guān)鍵類作以介紹。

Test:所有測(cè)試對(duì)象的基類。

CppUnit采用樹形結(jié)構(gòu)來(lái)組織管理測(cè)試對(duì)象(類似于目錄樹),因此這里采用了組合設(shè)計(jì)模式(Composite Pattern),Test的兩個(gè)直接子類TestLeaf和TestComposite分別表示“測(cè)試樹”中的葉節(jié)點(diǎn)和非葉節(jié)點(diǎn),其中TestComposite主要起組織管理的作用,就像目錄樹中的文件夾,而TestLeaf才是最終具有執(zhí)行能力的測(cè)試對(duì)象,就像目錄樹中的文件。

Test最重要的一個(gè)公共接口為:

virtual void run(TestResult *result) = 0;

其作用為執(zhí)行測(cè)試對(duì)象,將結(jié)果提交給result。

在實(shí)際應(yīng)用中,我們一般不會(huì)直接使用Test、TestComposite以及TestLeaf,除非我們要重新定制某些機(jī)制。

TestFixture:用于維護(hù)一組測(cè)試用例的上下文環(huán)境。

在實(shí)際應(yīng)用中,我們經(jīng)常會(huì)開發(fā)一組測(cè)試用例來(lái)對(duì)某個(gè)類的接口加以測(cè)試,而這些測(cè)試用例很可能具有相同的初始化和清理代碼。為此,CppUnit引入TestFixture來(lái)實(shí)現(xiàn)這一機(jī)制。

TestFixture具有以下兩個(gè)接口,分別用于處理測(cè)試環(huán)境的初始化與清理工作:

virtual void setUp(); 
virtual void tearDown(); 

TestCase:測(cè)試用例,從名字上就可以看出來(lái),它便是單元測(cè)試的執(zhí)行對(duì)象。

TestCase從Test和TestFixture多繼承而來(lái),通過把Test::run制定成模板函數(shù)(Template Method)而將兩個(gè)父類的操作融合在一起,run函數(shù)的偽定義如下:

// 偽代碼 
void TestCase::run(TestResult* result)
{
    result->startTest(this); // 通知result測(cè)試開始
    if( result->protect(this, &TestCase::setUp) ) // 調(diào)用setUp,初始化環(huán)境
        result->protect(this, &TestCase::runTest); // 執(zhí)行runTest,即真正的測(cè)試代碼
    result->protect(this, &TestCase::tearDown); // 調(diào)用tearDown,清理環(huán)境
    result->endTest(this); // 通知result測(cè)試結(jié)束
}

這里要提到的是函數(shù)runTest,它是TestCase定義的一個(gè)接口,原型如下:

virtual void runTest();

用戶需從TestCase派生出子類并實(shí)現(xiàn)runTest以開發(fā)自己所需的測(cè)試用例。

另外還要提到的就是TestResult的protect方法,其作用是對(duì)執(zhí)行函數(shù)(實(shí)際上是函數(shù)對(duì)象)的錯(cuò)誤信息(包括斷言和異常等)進(jìn)行捕獲,從而實(shí)現(xiàn)對(duì)測(cè)試結(jié)果的統(tǒng)計(jì)。

TestSuit:測(cè)試包,按照樹形結(jié)構(gòu)管理測(cè)試用例

TestSuit是TestComposite的一個(gè)實(shí)現(xiàn),它采用vector來(lái)管理子測(cè)試對(duì)象(Test),從而形成遞歸的樹形結(jié)構(gòu)。

TestCaller:TestCase適配器(Adapter),它將成員函數(shù)轉(zhuǎn)換成測(cè)試用例

雖然我們可以從TestCase派生自己的測(cè)試類,但從TestCase類的定義可以看出,它只能支持一個(gè)測(cè)試用例,這對(duì)于測(cè)試代碼的組織和維護(hù)很不方便,尤其是那些有共同上下文環(huán)境的一組測(cè)試。為此,CppUnit提供了TestCaller以解決這個(gè)問題。

TestCaller是一個(gè)模板類,它以實(shí)現(xiàn)了TestFixture接口的類為模板參數(shù),將目標(biāo)類中某個(gè)符合runTest原型的測(cè)試方法適配成TestCase的子類。

在實(shí)際應(yīng)用中,我們大多采用TestFixture和TestCaller相組合的方式,具體例子參見后文。

TestResult和TestListener:處理測(cè)試信息和結(jié)果

前面已經(jīng)提到,TestResult和TestListener采用了觀察者模式,TestResult維護(hù)一個(gè)注冊(cè)表,用于管理向其登記過的TestListener,當(dāng)TestResult收到測(cè)試對(duì)象(Test)的測(cè)試信息時(shí),再一一分發(fā)給它所管轄的TestListener。這一設(shè)計(jì)有助于實(shí)現(xiàn)對(duì)同一測(cè)試的多種處理方式。

TestFactory:測(cè)試工廠

這是一個(gè)輔助類,通過借助一系列宏定義讓測(cè)試用例的組織管理變得自動(dòng)化。參見后面的例子。

TestRunner:用于執(zhí)行測(cè)試用例

TestRunner將待執(zhí)行的測(cè)試對(duì)象管理起來(lái),然后供用戶調(diào)用。其接口為:

virtual void addTest( Test *test ); virtual void run( TestResult &controller, const std::string &testPath = "" );

這也是一個(gè)輔助類,需注意的是,通過addTest添加到TestRunner中的測(cè)試對(duì)象必須是通過new動(dòng)態(tài)創(chuàng)建的,用戶不能刪除這個(gè)對(duì)象,因?yàn)門estRunner將自行管理測(cè)試對(duì)象的生命期。

使用

先讓我們看看一個(gè)簡(jiǎn)單的例子:

#include <cppunit/TestCase.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>

// 定義測(cè)試用例
class SimpleTest : public CppUnit::TestCase
{
public:
    void runTest() // 重載測(cè)試方法
    {
        int i = 1;
        CPPUNIT_ASSERT_EQUAL(0, i);
    }
};

int main(int argc, char* argv[])
{
    CppUnit::TestResult r; 
    CppUnit::TestResultCollector rc;
    r.addListener(&rc); // 準(zhǔn)備好結(jié)果收集器 

    SimpleTest t;
    t.run(&r); // 運(yùn)行測(cè)試用例

    CppUnit::TextOutputter o(&rc, std::cout);
    o.write(); // 將結(jié)果輸出

    return 0;
}
編譯后運(yùn)行,輸出結(jié)果為:
!!!FAILURES!!!
Test Results:
Run: 1 Failures: 1 Errors: 0

1) test: (F) line: 18 E:/CppUnitExamples/SimpleTest.cpp
equality assertion failed
- Expected: 1
- Actual : 0

上面的例子很簡(jiǎn)單,需說明的是CPPUNIT_ASSERT_EQUAL宏。CppUnit定義了一組宏用于檢測(cè)錯(cuò)誤,CPPUNIT_ASSERT_EQUAL是其中之一,當(dāng)斷言失敗時(shí),CppUnit便會(huì)將錯(cuò)誤信息報(bào)告給TestResult。這些宏定義的說明如下:

CPPUNIT_ASSERT(condition):判斷condition的值是否為真,如果為假則生成錯(cuò)誤信息。

CPPUNIT_ASSERT_MESSAGE(message, condition):與CPPUNIT_ASSERT類似,但結(jié)果為假時(shí)報(bào)告messsage信息。

CPPUNIT_FAIL(message):直接報(bào)告messsage錯(cuò)誤信息。

CPPUNIT_ASSERT_EQUAL(expected, actual):判斷expected和actual的值是否相等,如果不等輸出錯(cuò)誤信息。

CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual):與CPPUNIT_ASSERT_EQUAL類似,但斷言失敗時(shí)輸出message信息。

CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta):判斷expected與actual的偏差是否小于delta,用于浮點(diǎn)數(shù)比較。

CPPUNIT_ASSERT_THROW(expression, ExceptionType):判斷執(zhí)行表達(dá)式expression后是否拋出ExceptionType異常。

CPPUNIT_ASSERT_NO_THROW(expression):斷言執(zhí)行表達(dá)式expression后無(wú)異常拋出。

接下來(lái)再看看TestFixture和TestCaller的組合使用:

#include <cppunit/TestCase.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestRunner.h>

// 定義測(cè)試類
class StringTest : public CppUnit::TestFixture
{
public:
    void setUp() // 初始化
    {
        m_str1 = "Hello, world";
        m_str2 = "Hi, cppunit";
    }

    void tearDown() // 清理
    {
    }

    void testSwap() // 測(cè)試方法1
    {
        std::string str1 = m_str1;
        std::string str2 = m_str2;
        m_str1.swap(m_str2);
        
        CPPUNIT_ASSERT(m_str1 == str2);
        CPPUNIT_ASSERT(m_str2 == str1);
    }

    void testFind() // 測(cè)試方法2
    {
        int pos1 = m_str1.find(',');
        int pos2 = m_str2.rfind(',');

        CPPUNIT_ASSERT_EQUAL(5, pos1);
        CPPUNIT_ASSERT_EQUAL(2, pos2);
    }

protected:
    std::string     m_str1;
    std::string     m_str2;
};

int main(int argc, char* argv[])
{
    CppUnit::TestResult r; 
    CppUnit::TestResultCollector rc;
    r.addListener(&rc); // 準(zhǔn)備好結(jié)果收集器 

    CppUnit::TestRunner runner; // 定義執(zhí)行實(shí)體
    runner.addTest(new CppUnit::TestCaller<StringTest>("testSwap", &StringTest::testSwap)); // 構(gòu)建測(cè)試用例1
    runner.addTest(new CppUnit::TestCaller<StringTest>("testFind", &StringTest::testFind)); // 構(gòu)建測(cè)試用例2
    runner.run(r); // 運(yùn)行測(cè)試

    CppUnit::TextOutputter o(&rc, std::cout);
    o.write(); // 將結(jié)果輸出

    return rc.wasSuccessful() ? 0 : -1;
}
編譯后運(yùn)行結(jié)果為:
OK (2 tests)

上面的代碼從功能上講沒有什么問題,但編寫起來(lái)太繁瑣了,為此,我們可以借助CppUnit定義的一套輔助宏,將測(cè)試用例的定義和注冊(cè)變得自動(dòng)化。上面的代碼改造后如下:

#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>
#include <cppunit/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>


// 定義測(cè)試類
class StringTest : public CppUnit::TestFixture
{
    CPPUNIT_TEST_SUITE(StringTest);  // 定義測(cè)試包
    CPPUNIT_TEST(testSwap);  // 添加測(cè)試用例1
    CPPUNIT_TEST(testFind);  // 添加測(cè)試用例2
    CPPUNIT_TEST_SUITE_END();  // 結(jié)束測(cè)試包定義
    
public:
    void setUp() // 初始化
    {
        m_str1 = "Hello, world";
        m_str2 = "Hi, cppunit";
    }

    void tearDown() // 清理
    {
    }

    void testSwap() // 測(cè)試方法1
    {
        std::string str1 = m_str1;
        std::string str2 = m_str2;
        m_str1.swap(m_str2);
        
        CPPUNIT_ASSERT(m_str1 == str2);
        CPPUNIT_ASSERT(m_str2 == str1);
    }

    void testFind() // 測(cè)試方法2
    {
        int pos1 = m_str1.find(',');
        int pos2 = m_str2.rfind(',');

        CPPUNIT_ASSERT_EQUAL(5, pos1);
        CPPUNIT_ASSERT_EQUAL(2, pos2);
    }

protected:
    std::string     m_str1;
    std::string     m_str2;
};

CPPUNIT_TEST_SUITE_REGISTRATION(StringTest); // 自動(dòng)注冊(cè)測(cè)試包

int main(int argc, char* argv[])
{
    CppUnit::TestResult r; 
    CppUnit::TestResultCollector rc;
    r.addListener(&rc); // 準(zhǔn)備好結(jié)果收集器 

    CppUnit::TestRunner runner; // 定義執(zhí)行實(shí)體
    runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
    runner.run(r); // 運(yùn)行測(cè)試

    CppUnit::TextOutputter o(&rc, std::cout);
    o.write(); // 將結(jié)果輸出

    return rc.wasSuccessful() ? 0 : -1;
}

CppUnit的簡(jiǎn)單介紹就到此,相信你已經(jīng)了解了其中的基本概念,也能夠開發(fā)單元測(cè)試代碼了。

轉(zhuǎn)自:http://blog.csdn.net/freefalcon/article/details/753819

posted @ 2012-03-01 20:25 周強(qiáng) 閱讀(266) | 評(píng)論 (0)編輯 收藏

分布式

     發(fā)現(xiàn)已經(jīng)很久沒寫博客了,主要前段時(shí)間實(shí)在太忙了,實(shí)習(xí),找工作,畢業(yè)答辯,經(jīng)歷了很多事情,現(xiàn)在終于空閑下來(lái)了。從明天開始要研究下分布式系統(tǒng)了,計(jì)劃設(shè)計(jì)實(shí)現(xiàn)個(gè)分布式數(shù)據(jù)庫(kù)。

posted @ 2011-12-25 23:49 周強(qiáng) 閱讀(217) | 評(píng)論 (0)編輯 收藏

江湖

    這兩天放假,又看了下笑傲江湖。看到笑傲江湖中曲洋和劉正風(fēng)雖然隸屬不同派別,因?yàn)橐袈沙蔀橹海献喑鲆磺缎Π两贰H松杏帜芘龅綆讉€(gè)能真正談心的知己呢。人生或許就像江湖,總會(huì)遇到很多人,很多事,總會(huì)遇到很多挫折,低谷。人生短短幾十載,應(yīng)該豁達(dá)些,沒必要去想那些煩心事,這世界牛人很多,我注定也是個(gè)小人物,我能做的也就是盡量做好自己能做的事。
   

posted @ 2011-08-13 23:45 周強(qiáng) 閱讀(409) | 評(píng)論 (5)編輯 收藏

僅列出標(biāo)題
共6頁(yè): 1 2 3 4 5 6 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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免费观看| 国产亚洲一区在线播放| 女同一区二区| 久久久五月婷婷| 美脚丝袜一区二区三区在线观看| 午夜精品久久久久久久99热浪潮| 亚洲第一福利在线观看| 亚洲伊人观看| 亚洲免费在线视频| 亚洲国产精品久久久久秋霞影院 | 久久精品国亚洲| 久久成年人视频| 美女图片一区二区| 欧美成人精品一区二区| 日韩视频第一页| 久久亚洲综合| 国产精品久久久久av免费| 国产精品一页| 日韩一级免费| 美女精品在线观看| 夜夜精品视频一区二区| 欧美亚洲综合久久| 欧美猛交免费看| 亚洲电影在线播放| 欧美专区18| 亚洲毛片av| 欧美成年人在线观看| 影音先锋亚洲精品| 亚洲欧美国产精品专区久久| 亚洲高清视频在线| 欧美在线免费观看| 国产性做久久久久久| 亚洲午夜性刺激影院| 9l视频自拍蝌蚪9l视频成人| 欧美成人午夜激情视频| 亚洲乱码国产乱码精品精| 亚洲精品1区2区| 欧美日韩国产综合新一区| 在线观看一区二区精品视频| 久久久亚洲国产美女国产盗摄| 亚洲欧美日韩国产一区二区| 国产精品视频精品| 久久久久五月天| 欧美一级精品大片| 国产日韩精品视频一区| 欧美在线观看一区二区| 亚洲视频第一页| 欧美午夜剧场| 久久久精品欧美丰满| 久久先锋资源| 亚洲一区二区三区精品动漫| 99精品热6080yy久久 | 欧美视频免费看| 先锋a资源在线看亚洲| 久久久免费精品视频| 一区二区三区av| 久久精品免费| 欧美一级播放| 欧美成人精品一区| 久久精品国产精品亚洲综合| 久久精品理论片| 午夜亚洲伦理| 欧美激情导航| 欧美高清日韩| 很黄很黄激情成人| 欧美一区二区观看视频| 亚洲视频 欧洲视频| 女女同性精品视频| 欧美中文字幕第一页| 国产精品久久久久aaaa| 9色精品在线| 99国内精品| 欧美色播在线播放| aa亚洲婷婷| 午夜国产精品影院在线观看| 亚洲第一精品福利| 好吊色欧美一区二区三区视频| 欧美成人日韩| 最近中文字幕mv在线一区二区三区四区 | 久久精品国产第一区二区三区最新章节 | 国产乱码精品一区二区三区忘忧草| 亚洲福利视频一区| 99精品欧美一区二区三区综合在线| 免费观看欧美在线视频的网站| 亚洲国产mv| 午夜日韩电影| 国内精品国产成人| 欧美国产视频一区二区| 99视频+国产日韩欧美| 久久国产99| 亚洲美女一区| 国产亚洲免费的视频看| 麻豆av一区二区三区久久| 亚洲毛片av在线| 毛片基地黄久久久久久天堂| 亚洲精品日韩在线| 国产精品社区| 牛人盗摄一区二区三区视频| 中文在线不卡| 日韩视频免费| 亚洲国产精品黑人久久久| 午夜精品成人在线视频| 亚洲精品五月天| 亚洲高清在线视频| 国产欧美1区2区3区| 国产精品h在线观看| 欧美成人一品| 免费不卡中文字幕视频| 欧美一区二区三区电影在线观看| 99re在线精品| 亚洲电影视频在线| 最近中文字幕mv在线一区二区三区四区| 国产人成一区二区三区影院| 欧美小视频在线| 国产精品久久久久77777| 亚洲综合精品四区| 亚洲一区视频在线| 欧美在线视频日韩| 久久在线视频| 欧美日韩日日夜夜| 国产精品一区三区| 国产一区二区主播在线| 亚洲国产裸拍裸体视频在线观看乱了中文 | 亚洲伦理在线| 一区二区三区你懂的| 欧美日韩精品国产| 欧美三级韩国三级日本三斤| 国产精品久久77777| 国产视频一区二区三区在线观看| 国产偷国产偷精品高清尤物| 亚洲国产成人久久综合一区| 亚洲人屁股眼子交8| 在线中文字幕日韩| 久久色在线播放| 欧美国产精品v| 久久福利精品| 国产精品xxxxx| 国产欧美日韩综合精品二区| 精品二区久久| 亚洲欧美日韩综合| 久久噜噜亚洲综合| 亚洲伦理中文字幕| 欧美在线免费观看视频| 欧美日韩视频专区在线播放 | 亚洲国产欧美不卡在线观看| 夜夜精品视频| 欧美黄色片免费观看| 午夜精品亚洲| 国产精品免费一区二区三区在线观看| 亚洲欧洲精品一区二区精品久久久| 欧美在现视频| 欧美影院视频| 在线日韩日本国产亚洲| 免费久久99精品国产自在现线| 日韩一区二区精品在线观看| 裸体女人亚洲精品一区| 亚洲成在人线av| 欧美sm重口味系列视频在线观看| 午夜精品久久久久99热蜜桃导演| 国产精品男人爽免费视频1| 亚洲一区二区三区精品在线| 亚洲精品人人| 国产伦精品一区二区三区四区免费| 亚洲欧美成人在线| 亚洲一区二区三区免费视频| 国产精品成人在线| 久久午夜电影网| 欧美精品精品一区| 欧美影视一区| 欧美激情在线免费观看| 亚洲欧美另类中文字幕| 久久aⅴ国产紧身牛仔裤| 亚洲二区视频| 久久精品夜色噜噜亚洲aⅴ | 久久岛国电影| 亚洲女女做受ⅹxx高潮| 久热精品视频在线观看| 一本久久a久久精品亚洲| 久久超碰97人人做人人爱| 日韩一级在线| 久久亚洲美女| 久久久久免费观看| 亚洲女爱视频在线| 亚洲精品美女| 老司机成人在线视频| 日韩亚洲在线| 欧美顶级少妇做爰| 亚洲成人在线视频播放| 国产一区二区看久久| 亚洲一二三区精品| 欧美精品日韩综合在线| 老司机免费视频一区二区三区| 国产精品一区二区三区久久 | 亚洲精品综合久久中文字幕| 久久久久一区二区三区四区| 久久久久国产免费免费| 国产一区欧美日韩| 久久一区二区三区av| 欧美福利电影网|