国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

拼多多C++面試現場:std::vector的底層實現

開發 開發工具
std::vector 是 C++ 標準庫中的一個強大工具,它是一個模板類,定義在<vector>頭文件中 ,就像是一個智能的動態數組容器。說它智能,是因為它能夠在運行時根據你的需求,自動調整自身的大小。

最近去參加了拼多多的C++ 面試,真可謂是一場充滿挑戰的技術大考驗!面試過程中,面試官突然拋出一個讓我心跳加速的問題:“請手撕 std::vector。” 這就好比在戰場上,敵人突然給你來個措手不及的襲擊 。

當時聽到這個題目,心里既緊張又興奮。緊張是因為現場手撕代碼本就壓力巨大,稍有不慎就可能出錯;興奮則是因為這是一個展示自己技術實力的好機會。std::vector 作為 C++ 標準庫中極為重要的容器,在日常開發里使用頻率超高,可真要在面試時現場實現它,還得把每個細節都處理好,那難度著實不小。

這個要求不僅考查對 C++ 語言特性的掌握程度,比如模板、內存管理等,還檢驗對數據結構和算法的理解。可以說,這道題就像一面鏡子,能清晰映照出面試者的技術功底是否扎實。 接下來,我就和大家詳細分享一下 std::vector 的實現思路以及其中涉及的關鍵知識點。

Part1.std::vector 基礎認知

1.1定義與功能簡述

std::vector 是 C++ 標準庫中的一個強大工具,它是一個模板類,定義在<vector>頭文件中 ,就像是一個智能的動態數組容器。說它智能,是因為它能夠在運行時根據你的需求,自動調整自身的大小。這就好比你有一個神奇的背包,一開始它可能是空的,容量也不大,但隨著你不斷往里面裝東西,它能自動變大,來容納更多物品,而且還會幫你管理好這些物品在內存中的存儲。

從底層實現來看,std::vector 在內存中維護著一塊連續的存儲空間,這使得它在訪問元素時有著極高的效率。你可以把它想象成一排緊密相連的小房間,每個房間都存放著一個元素,只要知道房間號(也就是元素的索引),就能瞬間找到對應的元素 。比如有個std::vector<int> numbers,當你想獲取第三個元素時,只需numbers[2]就能快速訪問到,這和傳統數組的訪問方式類似,但又比傳統數組多了動態管理大小的功能。

1.2在 C++ 編程中的廣泛應用場景

在數據處理領域,當你讀取一組數據,而這組數據的數量事先并不確定時,std::vector 就派上大用場了。例如,從文件中讀取一系列整數,你無需預先知道文件里到底有多少個整數,直接用std::vector<int>來存儲,它會自動根據讀取的數據量進行擴展。像下面這樣:

#include <iostream>
#include <vector>
#include <fstream>

int main() {
    std::vector<int> data;
    std::ifstream file("data.txt");
    int num;
    while (file >> num) {
        data.push_back(num);
    }
    // 后續可以對data進行各種處理
    return 0;
}

在算法實現方面,許多算法都依賴于能夠動態調整大小的數據結構。以排序算法為例,假設你要對一組動態生成的數字進行排序,使用std::vector來存儲這些數字,然后調用標準庫中的排序算法std::sort,就能輕松完成排序操作 :

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {5, 2, 8, 1, 9};
    std::sort(numbers.begin(), numbers.end());
    for (int num : numbers) {
        std::cout << num << " ";
    }
    return 0;
}

再比如在實現圖算法時,圖的節點和邊的數量往往是不確定的,std::vector可以用來存儲圖的鄰接表等數據結構,方便進行圖的遍歷、最短路徑計算等操作。可以說,在 C++ 編程的世界里,std::vector 就像一把萬能鑰匙,打開了許多復雜問題的解決之門。

Part2.手撕std::vector全過程

2.1關鍵接口實現

(1)push_back

實現思路:當調用push_back向std::vector中添加元素時,首先要檢查當前vector的容量(capacity)是否足夠。這就好比你有一個杯子,要往里倒水,得先看看杯子還有沒有空間。如果容量不足,就需要進行擴容操作 。

擴容操作:通常情況下,std::vector會以原大小的兩倍重新分配一塊新的內存空間。這是因為如果每次只增加一點點空間,可能會導致頻繁的內存分配和拷貝,效率很低。而翻倍擴容可以減少這種開銷。比如原來vector的容量是 4,當要添加第 5 個元素時,就會分配一塊容量為 8 的新內存 。

拷貝元素與釋放舊空間:分配好新內存后,要把原來vector中的元素逐個拷貝到新的內存空間中,這就像把舊杯子里的水小心翼翼地倒入新杯子。完成拷貝后,舊的內存空間就不再需要了,需要將其釋放,避免內存泄漏 。

插入新元素:最后,把要添加的新元素放入新內存空間的末尾。例如,有個std::vector<int> v,執行v.push_back(10),如果此時容量足夠,直接在末尾插入 10;如果容量不足,經過上述擴容等操作后,將 10 插入到新內存空間的末尾 。

(2)pop_back

刪除最后一個元素:pop_back的作用是刪除std::vector中的最后一個元素。它的實現邏輯相對簡單,直接將vector的大小(size)減 1 即可。這就好比你有一排擺放整齊的物品,把最后一個物品拿走,那么這排物品的數量就減少了 1 。

釋放內存空間:需要注意的是,雖然pop_back減少了元素數量,但vector占用的內存空間并不會立即釋放。這是因為如果頻繁釋放內存,后續又可能需要重新分配,會增加開銷。例如,std::vector<int> v = {1, 2, 3, 4, 5},執行v.pop_back()后,v的大小變為 4,最后一個元素 5 被 “刪除”,但內存中仍然保留著原來為 5 分配的空間,以備后續添加元素使用 。

(3)operator[]

重載運算符實現元素訪問:operator[]的作用是讓std::vector能夠像數組一樣通過下標來訪問元素。通過重載這個運算符,我們可以實現高效的隨機訪問。它的實現很直觀,就是返回指定下標位置的元素的引用。例如,有個std::vector<int> v = {10, 20, 30},當執行int num = v[1]時,operator[]會返回v中第二個元素(下標從 0 開始)的引用,也就是 20,這樣num就被賦值為 20 。

邊界檢查(可選):在實際實現中,標準庫的std::vector的operator[]并不進行邊界檢查,這是為了提高效率。但如果我們自己實現,也可以考慮添加邊界檢查,當訪問的下標超出vector的大小時,拋出異常或者返回一個默認值,以增強程序的健壯性 。

2.2內存管理機制剖析

(1)動態擴容策略

原理:當std::vector的容量不足以容納新元素時,就會觸發動態擴容。前面提到,一般會以原容量的兩倍來分配新的內存空間 。

示例:假設有一個初始std::vector<int> v,初始容量為 0,當第一次執行v.push_back(1)時,會分配一塊能容納 1 個元素的內存。當執行v.push_back(2)時,發現容量不足,就會重新分配一塊能容納 2 個元素的內存,把 1 拷貝到新內存,再把 2 放入新內存 。當繼續執行v.push_back(3)時,又會觸發擴容,分配一塊能容納 4 個元素的內存,將 1 和 2 拷貝過去,再放入 3 。

優點:這種翻倍擴容的策略有效地減少了內存分配的次數,因為每次擴容后的容量都能滿足后續多次添加元素的需求,避免了頻繁的小幅度擴容帶來的開銷 。

(2)內存釋放策略

特點:std::vector的內存占用只增不減,即使通過pop_back刪除元素,或者調用clear清空所有元素,其占用的內存空間也不會自動釋放 。這是因為考慮到后續可能還會添加元素,如果頻繁釋放和重新分配內存,會降低性能。

swap 技巧釋放內存:不過,我們可以利用swap技巧來釋放多余的內存。具體做法是創建一個臨時的std::vector,然后將當前vector與臨時vector進行swap操作。例如:

#include <iostream>
#include <vector>

void releaseExtraMemory(std::vector<int>& v) {
    std::vector<int>().swap(v);
}

int main() {
    std::vector<int> v;
    for (int i = 0; i < 100; i++) {
        v.push_back(i);
    }
    // 假設現在不需要這么多空間了
    releaseExtraMemory(v);
    std::cout << "Capacity after release: " << v.capacity() << std::endl;
    return 0;
}

在這個例子中,std::vector<int>()創建了一個臨時的空vector,它的容量通常為 0。通過swap操作,當前v的內存與臨時vector的內存進行了交換,這樣v就擁有了臨時vector的小容量(通常為 0),從而釋放了原來占用的大量內存,而臨時vector則擁有了原來v的大內存,但由于它是臨時的,在離開作用域時會自動銷毀,其占用的內存也會被釋放 。

2.3迭代器相關實現要點

(1)迭代器的作用和原理

作用:迭代器就像是一個 “指針”,用于遍歷std::vector中的元素。它提供了一種統一的方式來訪問容器中的元素,不管容器內部是如何存儲的 。使用迭代器,我們可以方便地進行元素的遍歷、查找、修改等操作。例如,通過迭代器可以實現對std::vector中所有元素的累加:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    int sum = 0;
    for (auto it = v.begin(); it != v.end(); ++it) {
        sum += *it;
    }
    std::cout << "Sum: " << sum << std::endl;
    return 0;
}

原理:std::vector的迭代器本質上是基于指針實現的。它可以指向vector中的某個元素,通過對迭代器進行自增(++)操作,可以使其指向下一個元素,就像指針在內存中移動一樣 。而且,由于std::vector的元素在內存中是連續存儲的,這種基于指針的迭代器能夠高效地遍歷元素 。

(2)迭代器失效場景及應對

插入元素導致迭代器失效:當在std::vector中插入元素時,如果插入操作導致了擴容,那么原來的所有迭代器都會失效。這是因為擴容后元素被拷貝到了新的內存空間,原來指向舊內存空間的迭代器就不再有效了。例如:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3};
    auto it = v.begin();
    v.push_back(4); // 可能觸發擴容
    if (it != v.end()) {
        std::cout << "Element: " << *it << std::endl; // 這里it可能失效,導致未定義行為
    }
    return 0;
}

刪除元素導致迭代器失效:從std::vector中刪除元素時,指向被刪除元素及其之后元素的迭代器都會失效。因為刪除元素后,后面的元素會向前移動,迭代器指向的位置就不再對應原來的元素了 。例如:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    auto it = v.begin();
    v.erase(it); // 刪除第一個元素
    while (it != v.end()) {
        std::cout << *it << " "; // 這里it已失效,會導致未定義行為
        ++it;
    }
    return 0;
}

應對方法:為了避免迭代器失效帶來的問題,在進行可能導致迭代器失效的操作后,要重新獲取迭代器。比如在插入或刪除元素后,使用操作返回的新迭代器來繼續操作 。例如:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    auto it = v.begin();
    it = v.erase(it); // 獲取刪除元素后的新迭代器
    while (it != v.end()) {
        std::cout << *it << " ";
        ++it;
    }
    return 0;
}

在這個例子中,erase操作返回了指向被刪除元素下一個元素的迭代器,我們用it接收這個新迭代器,從而避免了迭代器失效的問題 。

Part3.std::vector 源碼深度解讀

3.1關鍵數據結構與成員變量

⑴_Vector_base 基類結構

在深入剖析std::vector時,不能忽視其背后的_Vector_base基類。從繼承關系上看,std::vector通過保護繼承_Vector_base來獲取底層的內存管理等功能。在實際代碼中,_Vector_base主要負責內存的分配與釋放等關鍵操作 。例如,當std::vector需要擴容時,會調用_Vector_base中定義的內存分配函數。

在 GCC 的std::vector實現中,_Vector_base中定義了_M_allocate和_M_deallocate函數,分別用于分配和釋放內存 。當std::vector的容量不足時,就會通過_M_allocate函數來分配新的內存空間,這確保了std::vector能夠靈活地管理內存,滿足動態存儲元素的需求 。

⑵_Vector_impl_data 結構體

  • _Vector_impl_data結構體在std::vector的內存管理中扮演著重要角色,它包含了三個關鍵指針:_M_start、_M_finish和_M_end_of_storage 。_M_start指針指向當前已分配內存塊的第一個元素,就像指向一排房子的第一間 。_M_finish指針指向最后一個元素的下一個位置,它標記了當前已使用內存的邊界,比如一排房子中住了人的最后一間的下一間 。_M_end_of_storage指針則指向整個已分配內存的末尾,也就是這排房子的最后一間 。
  • 這三個指針相互配合,精確地管理著內存和元素。通過它們,可以輕松地獲取std::vector的大小(_M_finish - _M_start)和容量(_M_end_of_storage - _M_start) 。當需要添加新元素時,通過比較_M_finish和_M_end_of_storage,就能判斷是否需要擴容 。如果_M_finish等于_M_end_of_storage,就意味著當前內存已滿,需要進行擴容操作 。

3.2重要成員函數源碼解析

⑴insert_aux 函數

insert_aux函數是std::vector中處理插入元素的關鍵函數,其實現邏輯相當復雜且精妙 。當調用insert_aux插入元素時,首先要判斷當前std::vector的容量是否足夠 。如果容量不足,就需要進行擴容操作 。在擴容時,會以原容量的兩倍(通常情況)重新分配一塊新的內存空間 。例如,假設原std::vector的容量為 4,當要插入新元素且容量不足時,會分配一塊容量為 8 的新內存 。

接著,要進行元素的拷貝操作 。從插入位置開始,將原std::vector中插入位置及之后的元素依次拷貝到新內存中相應的位置 。這就好比將書架上從某一格開始的書,依次搬到新書架的對應位置 。然后,將新元素插入到指定位置 。完成插入和拷貝后,還需要更新_M_start、_M_finish和_M_end_of_storage這三個指針,以反映內存和元素的變化 。同時,由于插入操作可能會改變元素的位置,所有指向插入位置及之后元素的迭代器都會失效,需要重新獲取有效的迭代器 。

⑵erase 函數

erase函數用于刪除std::vector中的元素,它的實現主要涉及內存調整和迭代器更新 。當調用erase刪除指定位置的元素時,首先將刪除位置之后的元素依次向前移動一個位置,以填補被刪除元素留下的空缺 。例如,有個std::vector<int> v = {1, 2, 3, 4, 5},當執行v.erase(v.begin() + 2)刪除第三個元素 3 時,后面的 4 和 5 會向前移動,變成{1, 2, 4, 5} 。

移動元素后,_M_finish 指針需要向前移動一個位置,以反映當前 std::vector 的實際大小 。同時,指向被刪除元素及其之后元素的迭代器都會失效 。為了避免使用失效的迭代器導致未定義行為,在調用erase后,需要重新獲取有效的迭代器 。比如,可以使用erase 函數返回的迭代器,它指向被刪除元素的下一個元素,以此來繼續后續的操作 。

Part4.面試應對技巧與總結

4.1面試官考察意圖剖析

面試官出 “手撕 std::vector” 這道題,有著多方面的考察意圖。首先,是想檢驗面試者對 C++ 標準庫的理解程度。std::vector 作為 C++ 標準庫的重要組成部分,對它的深入理解,能反映出面試者對整個標準庫體系的掌握情況 。就像如果把 C++ 標準庫比作一座大廈,std::vector 就是大廈中一間關鍵的房間,了解這個房間的構造和功能,有助于理解整座大廈的布局 。

其次,這道題能考察面試者的編程能力。現場實現 std::vector,需要面試者熟練運用 C++ 語言特性,如模板、內存管理等知識,并且能夠將這些知識有機地結合起來,編寫出正確、高效的代碼 。這就如同廚師需要熟練運用各種食材和烹飪技巧,做出美味的菜肴一樣,面試者要熟練運用語言特性做出 “合格的代碼菜肴” 。

再者,面試官通過這道題來考察面試者的問題解決能力。在實現過程中,必然會遇到各種問題,比如內存分配失敗的處理、迭代器失效的解決等。面試者如何分析這些問題,找到解決方案,體現了其思維的邏輯性和靈活性 。這就好比在迷宮中尋找出口,面對各種岔路和障礙,能否找到正確的路徑,展現出面試者解決問題的能力 。

4.2回答該問題的要點與技巧

回答這個問題時,清晰闡述思路至關重要。在開始編碼前,先向面試官講解實現 std::vector 的整體流程,比如先介紹數據結構的設計,包括成員變量的定義和作用,再說明各個接口的實現思路,像push_back如何實現擴容、erase如何處理元素移動等 。就像建造房屋前先展示設計藍圖,讓面試官清楚了解你的 “建造計劃” 。

在實現過程中,要特別注意細節。例如,在進行內存分配時,要考慮分配失敗的情況,進行適當的錯誤處理;在操作迭代器時,要時刻關注迭代器失效的問題,并加以處理 。這些細節就像房屋建造中的小零件,雖然微小,但卻關乎整個 “房屋”(代碼)的穩定性和正確性 。

同時,要思考如何優化實現。比如在擴容時,選擇合適的擴容因子,以減少內存分配和拷貝的次數;在實現某些接口時,采用更高效的算法 。這就好比在房屋建造中,選擇更優質的材料和更合理的施工工藝,讓房屋更加堅固、美觀(代碼更加高效、健壯) 。

4.3對后續面試者的建議

對于后續準備面試的小伙伴們,一定要深入學習 C++ 知識。不僅要掌握 std::vector 這樣的標準庫容器,還要理解其背后的原理和設計思想 。可以通過閱讀相關書籍,如《C++ Primer》《Effective C++》等,深入鉆研 C++ 的語言特性和編程技巧 。

多做練習也是必不可少的。可以在 LeetCode、牛客網等在線平臺上,尋找與 C++ 編程相關的題目進行練習,尤其是關于數據結構和算法的題目,通過實踐來提高自己的編程能力 。這就像運動員通過大量的訓練來提高自己的競技水平一樣,面試者要通過大量練習來提升編程水平 。

此外,要善于總結面試經驗。每一次面試都是一次寶貴的學習機會,面試后要回顧自己的表現,分析回答得好的地方和存在的不足,不斷改進 。如果在面試中被問到某個問題回答得不好,面試后就去深入研究這個問題,確保下次遇到類似問題能夠應對自如 。

責任編輯:武曉燕 來源: 深度Linux
相關推薦

2025-09-01 02:15:00

2019-08-05 10:03:49

技術面試互聯網

2023-11-29 20:03:03

2024-06-03 08:09:46

2010-02-06 16:05:51

C++ Vector

2025-08-26 01:21:00

C++對象表達式

2025-06-05 08:05:00

vectorC++對象存儲

2023-10-04 00:38:30

C++原子

2025-07-15 03:00:00

2019-12-06 15:20:58

Redis獨立用戶數據庫

2024-02-26 00:05:00

C++開發

2025-06-24 08:05:00

函數重載編譯器編程

2021-01-06 07:32:10

996拼多多猝死

2025-04-08 00:00:00

@AsyncSpring異步

2022-04-13 14:43:05

JVM同步鎖Monitor 監視

2023-12-13 10:08:59

C++原子代碼

2023-11-24 16:13:05

C++編程

2024-10-15 10:59:18

Spring MVCJava開發

2019-01-28 05:10:36

拼多多電商促銷模型

2012-06-05 09:12:02

FacebookFolly
點贊
收藏

51CTO技術棧公眾號

97在线观看免费观看高清| 欧美专区中文字幕| 一区二区精品免费视频| 久久日本片精品aaaaa国产| 色婷婷久久久久swag精品| 日韩精品―中文字幕| 免费看的黄色欧美网站| 日韩女优人人人人射在线视频| 欧洲一区二区三区| 午夜国产精品一区| 电影天堂最新网址| 国产午夜亚洲精品不卡| 黄网站色视频免费观看| 久久精品国产清高在天天线| 亚洲qvod图片区电影| 青青一区二区| 国内伊人久久久久久网站视频 | 白嫩亚洲一区二区三区| 欧美激情亚洲| 欧美久久精品一级黑人c片| yjizz视频网站在线播放| 亚洲免费三区一区二区| 色综合影院在线观看| 天天操夜夜操国产精品| 欧美成年人视频| 欧美123区| 中文字幕在线看视频国产欧美在线看完整 | 成人久久久久| 成人成人成人在线视频| 深夜福利日韩在线看| 69免费视频| 成人av免费观看| 中文字幕一区二区三区四区五区 | 国产精品久久久久久久久动漫| 中文在线а√在线| 精品露脸国产偷人在视频| 国模吧一区二区三区| 国产小视频免费| 午夜免费欧美电影| 欧美性xxxxxxx| 精品无人区一区二区三区| 毛片网站大全| 亚洲久久一区二区| 亚洲三级 欧美三级| 成年人在线视频| 亚洲一区二区三区国产| 69精品丰满人妻无码视频a片| 91成人观看| 91精品国产99久久久久久| 欧美1区2区3| 欧美日韩成人黄色| 开心久久婷婷综合中文字幕| 亚洲成人免费视| 最近最好的中文字幕2019免费 | 精品国产不卡一区二区| 欧洲美女免费图片一区| 成人av资源在线观看| 欧美一区 二区| 污污的网站在线免费观看| 成人www视频在线观看| 在线视频亚洲专区| 国产亚洲精品美女久久久m| 一本色道精品久久一区二区三区| 亚洲国产精品一区二区第一页| 免费毛片在线不卡| 欧美精品性生活| 污污免费网站| xxxx成人| 精品国产sm最大网站| 91精品久久久久久综合五月天 | 国产伦一区二区三区色一情| 国产精品传媒入口麻豆| 456亚洲影院| 乱妇乱女熟妇熟女网站| 免费成人av在线| 中文字幕欧美国内| 亚洲人成久久| 黄色电影免费在线看| 久草在线资源站资源站| 精品成人在线视频| 欧美国产日韩一区| 欧美男女交配| 97久久久久久| 成人免费在线电影网| 久久人人爽爽人人爽人人片av| av电影天堂一区二区在线| 亚洲mv在线| 91精品久久久久久久久青青| 国产精品久久占久久| 日本一区免费| 九九热99久久久国产盗摄| 先锋资源久久| 久激情内射婷内射蜜桃| 日韩大陆毛片av| 亚洲一区日韩精品中文字幕| 亚洲午夜激情av| 亚洲在线视频一区| 精品国精品国产自在久国产应用| 伊人国产在线视频| 最近免费观看高清韩国日本大全| 国产午夜精品美女视频明星a级| 国产精品探花在线观看| 久久6免费高清热精品| www.国产精品一区| 欧美午夜在线| 日韩在线观看一区二区| 国产一级不卡毛片| 国产精品区一区二区三| 成人爽a毛片免费啪啪| 欧美怡红院视频一区二区三区| 99久久这里只有精品| 日韩精品久久久| 午夜欧美在线一二页| 亚洲一区二区三区免费| 欧美精彩视频一区二区三区| 亚洲欧美综合| 无码内射中文字幕岛国片| 欧美激情aⅴ一区二区三区| 日韩av高清在线播放| 亚洲欧洲另类| 一级网站免费观看| 国产亚洲精品美女久久久| 成人影视亚洲图片在线| av在线中文| 高清无码一区二区在线观看吞精| 亚洲国内精品视频| 老司机精品久久| 成人影院在线观看| 永久久久久久| 亚洲人线精品午夜| 欧美一区=区| 欧美激情图区| 亚洲一区在线观看免费观看电影高清| 欧美极品欧美精品欧美视频| 成人深夜视频在线观看| 精品一区二区三区在线| 日本aⅴ中文| 欧美日韩国产天堂| 高潮久久久久久久久久久久久久| 日韩av影视| 国产女人精品视频| 欧美亚洲日本黄色| 亚洲精品无人区| 91骚色在线| 阿v免费在线观看| 99成人在线视频| 青青草一区二区三区| 久久丝袜美腿综合| 欧美一卡二卡在线观看| 久久久久久久久久国产精品| 午夜精品区一区二区三| 国产精品沙发午睡系列| 手机av免费在线| 精品69视频一区二区三区Q| 99re视频精品| 日韩一区二区精品| 国产传媒一区二区三区| 蜜桃臀av在线| 偷拍中文亚洲欧美动漫| 亚州av一区| 日韩av中文字幕一区二区三区| 久久综合久久综合亚洲| 制服丝袜成人动漫| 欧美一区第一页| 国产一区再线| 日本成人黄色网址| 男人和女人做事情在线视频网站免费观看| 在线免费黄色| 国产精品一区二区美女视频免费看 | 国产精品wwwwww| 91麻豆精品国产无毒不卡在线观看 | 亚洲国产成人精品久久久国产成人一区| 国产不卡视频在线观看| 丰满少妇一区| 亚洲永久精品免费| 缅甸午夜性猛交xxxx| 国产精品久久久久久久久久久久午夜片| 欧美一区二区三区的| 中文字幕日韩av资源站| 成人午夜电影小说| 一区2区3区在线看| 欧美v亚洲v综合ⅴ国产v| 美国一区二区三区在线播放 | 国产日产欧美一区二区视频| 欧美精品久久一区| 国产伦精品一区二区三区照片91| 国产一级做a爰片久久| 高清日韩欧美| 一区二区激情小说| 国产综合香蕉五月婷在线| 一级片在线视频| 欧美国产美女| 在线观看91精品国产入口| 99久久国产免费免费| 黄色在线观看视频网站| 国产乱人伦精品一区二区在线观看 | 黄色一级免费大片| 日本免费在线视频| 99精品一区| 在线免费观看日韩欧美|