一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - C++中vector迭代器失效問題詳解

C++中vector迭代器失效問題詳解

2022-02-24 14:24~怎么回事啊~ C/C++

vector是向量類型,它可以容納許多類型的數據,如若干個整數,所以稱其為容器,這篇文章主要給大家介紹了關于C++中vector迭代器失效問題的相關資料,需要的朋友可以參考下

問題:

(1)刪除vector中所有的偶數

#include <iostream>
#include <vector>

using namespace std;

int main()
{
vector<int> vec;
for (int i = 0; i < 10; ++i) {
  vec.push_back(i);
}

//把vec容器中的所有偶數刪除
auto it = vec.begin();
for (; it != vec.end(); ++it) {
  if ((*it) % 2 == 0) {
    vec.erase(it);
  }
}
return 0;
}

運行導致程序崩潰!

(2)vector容器插入元素問題

#include <iostream>
#include <vector>

using namespace std;

int main()
{
vector<int> vec;
for (int i = 0; i < 10; ++i) {
  vec.push_back(i);
}

//把vec容器中的所有偶數前面添加一個小于偶數值1的數字
auto it = vec.begin();
for (; it != vec.end(); ++it) {
  if ((*it) % 2 == 0) {
    vec.insert(it,*it-1);
  }
}
return 0;
}

運行導致程序崩潰!

原因:iterator失效

C++中vector迭代器失效問題詳解

當刪除(獲取增加)it位置的元素時,導致it后面的迭代器全部失效。因此多次調用erase insert導致崩潰

 

迭代器失效原因

1 當容器調用erase時,當前位置到容器末尾元素的所有的迭代器全部失效

2 當容器調用insert時,當前位置到容器末尾元素的所有的迭代器全部失效;

3 當容器調用insert時,如果引起容器內存擴容,原來容器的所有的迭代器就全部失效

 

解決:

進行更新操作:erase(insert)后會返回指向下一個元素的迭代器

C++中vector迭代器失效問題詳解

解釋:vector::erase - C++ Reference

從向量中刪除單個元素(位置)或一系列元素([第一、最后一個])。
這有效地減少了容器的大小,減少了被刪除的元素的數量,這些元素會被銷毀。
由于向量使用數組作為其底層存儲,擦除向量端以外位置的元素會導致容器在段擦除后將所有元素重新定位到其新位置。與其他類型的序列容器對相同操作執行的操作相比,這通常是一種低效的操作(如列表或轉發列表)。

同理有:vector::insert - C++ Reference

C++中vector迭代器失效問題詳解

通過在指定位置的元素之前插入新元素來擴展向量,從而通過插入的元素數量有效地增加容器大小。

當且僅當新向量大小超過當前向量容量時,這會導致自動重新分配分配分配的存儲空間

因為向量使用數組作為其底層存儲,所以在向量末端以外的位置插入元素會導致容器將位置之后的所有元素重新定位到它們的新位置。與其他類型的序列容器(如list或forward_list)對相同操作執行的操作相比,這通常是一種低效的操作。
這些參數確定插入的元素數量及其初始化值:

也說明了進行插入操作會導致之后的迭代器失效

修改代碼:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
vector<int> vec;
for (int i = 0; i < 10; ++i) {
  vec.push_back(i);
}

//把vec容器中的所有偶數刪除
auto it = vec.begin();
while (it!=vec.end())
{
  if ((*it) % 2 == 0) {
    it = vec.erase(it);
  }
  else {
    it++;
  }
}

for(auto it:vec) {
  cout << it << " ";
}
return 0;
}
#include <iostream>
#include <vector>

using namespace std;

int main()
{
vector<int> vec;
for (int i = 0; i < 10; ++i) {
  vec.push_back(i);
}

//把vec容器中的所有偶數前面添加一個小于偶數值1的數字
auto it = vec.begin();
for (; it != vec.end(); ++it) {
  if ((*it) % 2 == 0) {
    it = vec.insert(it, *it - 1);
    //it原來的位置插入了新的,需要++it兩次,才能到該偶數的后一個元素
    ++it;
  }
}

for (auto val : vec) {
  cout << val << " ";
}
return 0;
}

這樣就沒有問題。

vector中實現 ??????

http://www.ythuaji.com.cn/article/226666.html接該文最終實現的vector上繼續:

頭插法:

C++中vector迭代器失效問題詳解

檢查迭代器失效:

在進行刪除或增加的時候,要檢測該位置到last位置,使其迭代器失效

void pop_back() // 從容器末尾刪除元素
{
  if (empty())
    return;

  //檢查迭代器 從該位置到最后
  verify(_last-1,_last);

  // 不僅要把_last指針--,還需要析構刪除的元素
  --_last;
  _allocator.destroy(_last);
}
//檢查迭代器失效
void verify(T* first, T* last) {
  Iterator_Base * pre = &this->_head;
  Iterator_Base * it = this->_head._next;

  while (it != nullptr) {
    if (it->_cur->_ptr > first && it->_cur->_ptr <= last) {
      it->_cur->_pVec = nullptr;//迭代器失效,把iterator持有的容器指針置空
      pre->_next = it->_next;//刪除當前迭代器節點,繼續判斷后面的迭代器是否失效
      delete it;
      it = pre->_next;
    }
    else {
      pre = it;
      it = it->_next;
    }
  
  }
}

C++中vector迭代器失效問題詳解

insert

//insert
iterator insert(iterator it, const T&val) {
   //未考慮擴容和it._ptr的合法性 todo
  verify(it._ptr - 1, _last);
  //依次向后移動一個位置
  T*p = _last;
  while (p > it->_ptr) {
    _allocator.construct(p,*(p-1));
    _allocator.destroy(p-1);
    p--;
  }

  //在該位置插入
  _allocator.construct(p, val);
  _last++;
  return iterator(this, p);//生成新的迭代器
}

erase

#include <iostream>

//容器的空間配置器
template <typename T>
struct Allocator
{
T* allocate(size_t size)//只負責內存開辟
{
  return (T*)malloc(sizeof(T) * size);
}
void deallocate(void *p)//只負責內存釋放
{
  free(p);
}
void construct(T *p, const T &val)//已經開辟好的內存上,負責對象構造
{
  new (p) T(val);//定位new,指定內存上構造val,T(val)拷貝構造
}
void destroy(T *p)//只負責對象析構
{
  p->~T();//~T()代表了T類型的析構函數
}
};

template <typename T, typename Alloc = Allocator<T>>
class vector//向量容器
{
public:
vector(int size = 10)//構造
{
  //_first = new T[size];
  _first = _allocator.allocate(size);
  _last = _first;
  _end = _first + size;
}
~vector()//析構
{
  //delete[]_first;
  for (T *p = _first; p != _last; ++p)
  {
    _allocator.destroy(p);//把_first指針指向的數組的有效元素析構
  }
  _allocator.deallocate(_first);//釋放堆上的數組內存
  _first = _last = _end = nullptr;
}
vector(const vector<T> &rhs)//拷貝構造
{
  int size = rhs._end - rhs._first;//空間大小
  //_first = new T[size];
  _first = _allocator.allocate(size);
  int len = rhs._last - rhs._first;//有效元素
  for (int i = 0; i < len; ++i)
  {
    //_first[i] = rhs._first[i];
    _allocator.construct(_first + i, rhs._first[i]);
  }
  _last = _first + len;
  _end = _first + size;
}
vector<T>& operator=(const vector<T> &rhs)//賦值運算符重載
{
  if (this == &rhs)
  {
    return *this;
  }

  //delete[]_first;
  for (T *p = _first; p != _last; ++p)
  {
    _allocator.destory(p);//把_first指針指向的數組的有效元素析構
  }
  _allocator.deallocate(_first);//釋放堆上的數組內存

  int size = rhs._end - rhs._first;//空間大小
  _first = _allocator.allocate(size);
  int len = rhs._last - rhs._first;//有效元素
  for (int i = 0; i < len; ++i)
  {
    _allocator.construct(_first + i, rhs._first[i]);
  }
  _last = _first + len;
  _end = _first + size;
  return *this;
}
void push_back(const T &val)//尾插
{
  if (full())
  {
    expand();
  }
  //*_last++ = val;
  _allocator.construct(_last, val);//_last指針指向的內存構造一個值為val的對象
  _last++;
}
void pop_back()//尾刪
{
  if (empty()) return;
  verify(_last - 1, _last);
  //erase(it); verift(it._ptr, _last);
  //insert(it,val); verift(it._ptr, _last);
  //--_last;
  //不僅要把_last指針--,還需要析構刪除的元素
  --_last;
  _allocator.destroy(_last);
}
T back()const//返回容器末尾元素值
{
  return *(_last - 1);
}
bool full()const
{
  return _last == _end;
}
bool empty()const
{
  return _first == _last;
}
int size()const//返回容器中元素個數
{
  return _last - _first;
}
T& operator[](int index)
{
  if (index < 0 || index >= size())
  {
    throw "OutOfRangeException";
  }
  return _first[index];
}
//迭代器一般實現成容器的嵌套類型
class iterator
{
public:
  friend class vector <T, Alloc>;
  //新生成當前容器某一個位置元素的迭代器
  iterator(vector<T, Alloc> *pvec = nullptr
    , T *ptr = nullptr)
    :_ptr(ptr), _pVec(pvec)
  {
    Iterator_Base *itb = new Iterator_Base(this, _pVec->_head._next);
    _pVec->_head._next = itb;
  }
  bool operator!=(const iterator &it)const
  {
    //檢查迭代器的有效性
    if (_pVec == nullptr || _pVec != it._pVec)//迭代器為空或迭代兩個不同容器
    {
      throw "iterator incompatable!";
    }
    return _ptr != it._ptr;
  }
  void operator++()
  {
    //檢查迭代器有效性
    if (_pVec == nullptr)
    {
      throw "iterator incalid!";
    }
    _ptr++;
  }
  T& operator*()
  {
    //檢查迭代器有效性
    if (_pVec == nullptr)
    {
      throw "iterator invalid!";
    }
    return *_ptr;
  }
  const T& operator*()const
  {
    if (_pVec == nullptr)
    {
      throw "iterator invalid!";
    }
    return *_ptr;
  }
private:
  T *_ptr;
  //當前迭代器是哪個容器對象
  vector<T, Alloc> *_pVec;//指向當前對象容器的指針
};
iterator begin()
{
  return iterator(this, _first);
}
iterator end()
{
  return iterator(this, _last);
}
//檢查迭代器失效
void verify(T *first, T *last)
{
  Iterator_Base *pre = &this->_head;
  Iterator_Base *it = this->_head._next;
  while (it != nullptr)
  {
    if (it->_cur->_ptr > first && it->_cur->_ptr <= last)
    {
      //迭代器失效,把iterator持有的容器指針置nullptr
      it->_cur->_pVec = nullptr;
      //刪除當前迭代器節點,繼續判斷后面的迭代器節點是否失效
      pre->_next = it->_next;
      delete it;
      it = pre->_next;
    }
    else
    {
      pre = it;
      it = it->_next;
    }
  }
}

//自定義vector容器insert方法實現
iterator insert(iterator it, const T &val)
{
  //1.這里我們未考慮擴容
  //2.還未考慮it._ptr指針合法性,假設它合法
  verify(it._ptr - 1, _last);
  T *p = _last;
  while (p > it._ptr)
  {
    _allocator.construct(p, *(p - 1));
    _allocator.destroy(p - 1);
    p--;
  }
  _allocator.construct(p, val);
  _last++;
  return iterator(this, p);
}

//自定義vector容器erase方法實現
iterator erase(iterator it)
{
  verify(it._ptr - 1, _last);
  T *p = it._ptr;
  while (p < _last - 1)
  {
    _allocator.destroy(p);
    _allocator.construct(p, *(p + 1));
    p++;
  }
  _allocator.destroy(p);
  _last--;
  return iterator(this, it._ptr);
}
private:
T *_first;//起始數組位置
T *_last;//指向最后一個有效元素后繼位置
T *_end;//指向數組空間的后繼位置
Alloc _allocator;//定義容器的空間配置器對象

//容器迭代器失效增加代碼
struct Iterator_Base
{
  Iterator_Base(iterator *c = nullptr, Iterator_Base *n = nullptr)
    :_cur(c), _next(n) {}
  iterator *_cur;
  Iterator_Base *_next;
};
Iterator_Base _head;

void expand()//擴容
{
  int size = _end - _first;
  //T *ptmp = new T[2*size];
  T *ptmp = _allocator.allocate(2 * size);
  for (int i = 0; i < size; ++i)
  {
    _allocator.construct(ptmp + i, _first[i]);
    //ptmp[i] = _first[i];
  }
  //delete[]_first;
  for (T *p = _first; p != _last; ++p)
  {
    _allocator.destroy(p);
  }
  _allocator.deallocate(_first);
  _first = ptmp;
  _last = _first + size;
  _end = _first + 2 * size;
}
};

int main()
{
vector<int>   vec(200);

for (int i = 0; i < 10; ++i) {
  vec.push_back(i);
}

//把vec容器中的所有偶數前面添加一個小于偶數值1的數字
auto it = vec.begin();
for (; it != vec.end(); ++it) {
  if ((*it) % 2 == 0) {
    it = vec.insert(it, *it - 1);
    //it原來的位置插入了新的,需要++it兩次,才能到該偶數的后一個元素
    ++it;
  }
}

for (auto val : vec) {
  std::cout << val << " ";
}

return 0;
}

測試vector

#include <iostream>

//容器的空間配置器
template <typename T>
struct Allocator
{
T* allocate(size_t size)//只負責內存開辟
{
  return (T*)malloc(sizeof(T) * size);
}
void deallocate(void *p)//只負責內存釋放
{
  free(p);
}
void construct(T *p, const T &val)//已經開辟好的內存上,負責對象構造
{
  new (p) T(val);//定位new,指定內存上構造val,T(val)拷貝構造
}
void destroy(T *p)//只負責對象析構
{
  p->~T();//~T()代表了T類型的析構函數
}
};

template <typename T, typename Alloc = Allocator<T>>
class vector//向量容器
{
public:
vector(int size = 10)//構造
{
  //_first = new T[size];
  _first = _allocator.allocate(size);
  _last = _first;
  _end = _first + size;
}
~vector()//析構
{
  //delete[]_first;
  for (T *p = _first; p != _last; ++p)
  {
    _allocator.destroy(p);//把_first指針指向的數組的有效元素析構
  }
  _allocator.deallocate(_first);//釋放堆上的數組內存
  _first = _last = _end = nullptr;
}
vector(const vector<T> &rhs)//拷貝構造
{
  int size = rhs._end - rhs._first;//空間大小
  //_first = new T[size];
  _first = _allocator.allocate(size);
  int len = rhs._last - rhs._first;//有效元素
  for (int i = 0; i < len; ++i)
  {
    //_first[i] = rhs._first[i];
    _allocator.construct(_first + i, rhs._first[i]);
  }
  _last = _first + len;
  _end = _first + size;
}
vector<T>& operator=(const vector<T> &rhs)//賦值運算符重載
{
  if (this == &rhs)
  {
    return *this;
  }

  //delete[]_first;
  for (T *p = _first; p != _last; ++p)
  {
    _allocator.destory(p);//把_first指針指向的數組的有效元素析構
  }
  _allocator.deallocate(_first);//釋放堆上的數組內存

  int size = rhs._end - rhs._first;//空間大小
  _first = _allocator.allocate(size);
  int len = rhs._last - rhs._first;//有效元素
  for (int i = 0; i < len; ++i)
  {
    _allocator.construct(_first + i, rhs._first[i]);
  }
  _last = _first + len;
  _end = _first + size;
  return *this;
}
void push_back(const T &val)//尾插
{
  if (full())
  {
    expand();
  }
  //*_last++ = val;
  _allocator.construct(_last, val);//_last指針指向的內存構造一個值為val的對象
  _last++;
}
void pop_back()//尾刪
{
  if (empty()) return;
  verify(_last - 1, _last);
  //erase(it); verift(it._ptr, _last);
  //insert(it,val); verift(it._ptr, _last);
  //--_last;
  //不僅要把_last指針--,還需要析構刪除的元素
  --_last;
  _allocator.destroy(_last);
}
T back()const//返回容器末尾元素值
{
  return *(_last - 1);
}
bool full()const
{
  return _last == _end;
}
bool empty()const
{
  return _first == _last;
}
int size()const//返回容器中元素個數
{
  return _last - _first;
}
T& operator[](int index)
{
  if (index < 0 || index >= size())
  {
    throw "OutOfRangeException";
  }
  return _first[index];
}
//迭代器一般實現成容器的嵌套類型
class iterator
{
public:
  friend class vector <T, Alloc>;
  //新生成當前容器某一個位置元素的迭代器
  iterator(vector<T, Alloc> *pvec = nullptr
    , T *ptr = nullptr)
    :_ptr(ptr), _pVec(pvec)
  {
    Iterator_Base *itb = new Iterator_Base(this, _pVec->_head._next);
    _pVec->_head._next = itb;
  }
  bool operator!=(const iterator &it)const
  {
    //檢查迭代器的有效性
    if (_pVec == nullptr || _pVec != it._pVec)//迭代器為空或迭代兩個不同容器
    {
      throw "iterator incompatable!";
    }
    return _ptr != it._ptr;
  }
  void operator++()
  {
    //檢查迭代器有效性
    if (_pVec == nullptr)
    {
      throw "iterator incalid!";
    }
    _ptr++;
  }
  T& operator*()
  {
    //檢查迭代器有效性
    if (_pVec == nullptr)
    {
      throw "iterator invalid!";
    }
    return *_ptr;
  }
  const T& operator*()const
  {
    if (_pVec == nullptr)
    {
      throw "iterator invalid!";
    }
    return *_ptr;
  }
private:
  T *_ptr;
  //當前迭代器是哪個容器對象
  vector<T, Alloc> *_pVec;//指向當前對象容器的指針
};
iterator begin()
{
  return iterator(this, _first);
}
iterator end()
{
  return iterator(this, _last);
}
//檢查迭代器失效
void verify(T *first, T *last)
{
  Iterator_Base *pre = &this->_head;
  Iterator_Base *it = this->_head._next;
  while (it != nullptr)
  {
    if (it->_cur->_ptr > first && it->_cur->_ptr <= last)
    {
      //迭代器失效,把iterator持有的容器指針置nullptr
      it->_cur->_pVec = nullptr;
      //刪除當前迭代器節點,繼續判斷后面的迭代器節點是否失效
      pre->_next = it->_next;
      delete it;
      it = pre->_next;
    }
    else
    {
      pre = it;
      it = it->_next;
    }
  }
}

//自定義vector容器insert方法實現
iterator insert(iterator it, const T &val)
{
  //1.這里我們未考慮擴容
  //2.還未考慮it._ptr指針合法性,假設它合法
  verify(it._ptr - 1, _last);
  T *p = _last;
  while (p > it._ptr)
  {
    _allocator.construct(p, *(p - 1));
    _allocator.destroy(p - 1);
    p--;
  }
  _allocator.construct(p, val);
  _last++;
  return iterator(this, p);
}

//自定義vector容器erase方法實現
iterator erase(iterator it)
{
  verify(it._ptr - 1, _last);
  T *p = it._ptr;
  while (p < _last - 1)
  {
    _allocator.destroy(p);
    _allocator.construct(p, *(p + 1));
    p++;
  }
  _allocator.destroy(p);
  _last--;
  return iterator(this, it._ptr);
}
private:
T *_first;//起始數組位置
T *_last;//指向最后一個有效元素后繼位置
T *_end;//指向數組空間的后繼位置
Alloc _allocator;//定義容器的空間配置器對象

//容器迭代器失效增加代碼
struct Iterator_Base
{
  Iterator_Base(iterator *c = nullptr, Iterator_Base *n = nullptr)
    :_cur(c), _next(n) {}
  iterator *_cur;
  Iterator_Base *_next;
};
Iterator_Base _head;

void expand()//擴容
{
  int size = _end - _first;
  //T *ptmp = new T[2*size];
  T *ptmp = _allocator.allocate(2 * size);
  for (int i = 0; i < size; ++i)
  {
    _allocator.construct(ptmp + i, _first[i]);
    //ptmp[i] = _first[i];
  }
  //delete[]_first;
  for (T *p = _first; p != _last; ++p)
  {
    _allocator.destroy(p);
  }
  _allocator.deallocate(_first);
  _first = ptmp;
  _last = _first + size;
  _end = _first + 2 * size;
}
};

int main()
{
vector<int>   vec(200);

for (int i = 0; i < 10; ++i) {
  vec.push_back(i);
}

//把vec容器中的所有偶數前面添加一個小于偶數值1的數字
auto it = vec.begin();
for (; it != vec.end(); ++it) {
  if ((*it) % 2 == 0) {
    it = vec.insert(it, *it - 1);
    //it原來的位置插入了新的,需要++it兩次,才能到該偶數的后一個元素
    ++it;
  }
}

for (auto val : vec) {
  std::cout << val << " ";
}

return 0;
}

 

總結

到此這篇關于C++中vector迭代器失效問題的文章就介紹到這了,更多相關C++中vector迭代器失效內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/LIJIWEI0611/article/details/121318554

延伸 · 閱讀

精彩推薦
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
主站蜘蛛池模板: 高h扶她文肉 | 放荡警察巨r麻麻出轨小说 范冰冰特黄xx大片 饭冈加奈子在线播放观看 法国老妇性xx在线播放 | 国产精品午夜国产小视频 | 国产目拍亚洲精品一区二区三区 | 国产一区视频在线免费观看 | 欧美日韩一区二区中文字幕视频 | 色综合天天网 | 国产ay | 国产成人精品免费视频大全五级 | 美女扒开腿让男人桶爽免费gif | 亚洲白拍 | 91视在线国内在线播放酒店 | 香蕉久久ac一区二区三区 | 波多 在线播放 | 日本黄色大片免费观看 | 国产高清视频一区二区 | 欧美艳星kagney1ynn | 国产成人亚洲精品91专区手机 | 国产福利一区二区精品视频 | 四虎影视黄色 | 成人福利免费视频 | 性色欲情网站IWWW九文堂 | 免费一级毛片在级播放 | 欧美日本一道高清免费3区 欧美人做人爱a全程免费 | 午夜国产精品影院在线观看 | 皇上撞着太子妃的秘密小说 | 贵妇的私人性俱乐部 | 精品区卡一卡2卡三免费 | 国产美女极品免费视频 | 高清在线观看免费 | 出差被灌醉绝伦的上司日本 | 精品国产午夜久久久久九九 | 极品妖艳许清赵丽全文免费阅读 | 青草香蕉精品视频在线观看 | 欧美靠逼视频 | 欧美综合一区二区三区 | 国产福利专区精品视频 | 久久综合狠狠综合久久综合88 | 国产精品林美惠子在线观看 | 午夜人妻理论片天堂影院 | 丝袜捆绑调教丨vk |