辨析std::vector::erase和std::remove (未完待續)

std::vector::erase

#include <vector>
詳見: http://www.cplusplus.com/reference/vector/vector/erase/

iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);
Erase elements
Removes from the vector either a single element (position) or a range of elements ([first,last)).
Return value
An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.
Example
// erasing from vector
#include <iostream>
#include <vector>

int main ()
{
  std::vector<int> myvector;

  // set some values (from 1 to 10)
  for (int i=1; i<=10; i++) myvector.push_back(i);

  // erase the 6th element
  myvector.erase (myvector.begin()+5);

  // erase the first 3 elements:
  myvector.erase (myvector.begin(),myvector.begin()+3);

  std::cout << "myvector contains:";
  for (unsigned i=0; i<myvector.size(); ++i)
    std::cout << ' ' << myvector[i];
  std::cout << '\n';

  return 0;
}

Output

myvector contains: 4 5 7 8 9 10
erase的作用是刪除迭代器position對應的元素並返回對應下一個元素的迭代器.
我看網上有這樣的erase內部實現, 就想研究下erase內部到底幹了什麼.
iterator erase(iterator position)
{
  if(position + 1 !=end())
  {
     copy(position + 1,finish,position);
  }
  finish--;
  destroy(finish);
  return position;
}

std::copy

#include <algorithm>
template <class InputIterator, class OutputIterator>
  OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result);

Copy range of elements
Copies the elements in the range [first,last) into the range beginning at result.
The function returns an iterator to the end of the destination range (which points to the element following the last element copied).
The ranges shall not overlap in such a way that result points to an element in the range [first,last). For such cases, see copy_backward.
The behavior of this function template is equivalent to:

template<class InputIterator, class OutputIterator>
  OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
{
  while (first!=last) {
    *result = *first;
    ++result; ++first;
  }
  return result;
}
erase中copy的作用就是將position+1到finish之間的數據移動到以position開始的位置, 也就是前移一位.
這裏有些地方不明白:
1. finish是什麼?
2. 爲何前移之後要destroy(finish)? 難道前移自動就將position元素移動到finish的位置了嗎?

std::allocator::destroy

#include <memory>
template <class U>
  void destroy (U* p);
Destroy an object
Destroys in-place the object pointed by p.
Notice that this does not deallocate the storage for the element (see memberdeallocate to release storage space).
The function uses U's destructor, as if the following code was used:
p->~U();
這裏說沒有deallocate元素的存儲空間, 但是調用了析構函數? 我自己寫了一段代碼希望研究下erase:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

class pig{
private:
	int num;
public:
	pig(int n) : num(n){}
	~pig(){
		cout << "Pig " << num << " died!" << endl;
		num = 0;
	}
	int grunt(){ return num; }
	bool operator==(const pig& p){ return this->num == p.num; }
};
// I have to name differently the following two functions to prevent error from the 'find' function.
void gruntPigPt(pig *p){ cout << "Pig: " << p->grunt() << endl; }
void gruntPig(pig p){ cout << "Pig: " << p.grunt() << endl; }

void test1(){
	cout << "------------ Round One : Pig Pointers ------------" << endl;
	vector<pig*> v;
	pig *second = NULL;
	for(int i = 1; i <= 5; ++i){
		pig *p = new pig(i);
		if(i == 2) second = p;
		v.push_back(p);
	}
	for_each(v.begin(), v.end(), gruntPigPt);
	auto it = find(v.begin(), v.end(), second); // To support 'auto', C++ 11 is needed.
	cout << "Found you! Pig: " << (*it)->grunt() << endl;
	it = v.erase(it);
	cout << "You are the next! Pig: " << (*it)->grunt() << endl;
	cout << "Here is Pig:" << second->grunt() << endl;
	delete second;
	for(int i = v.size() - 1; i >= 0; --i){
		pig *p = v.back(); v.pop_back();
		delete p;
	}
}

void test2(){
	cout << "------------ Round Two : Pigs ------------" << endl;
	vector<pig> v;
	for(int i = 1; i <= 5; ++i){
		pig p(i);
		v.push_back(p);
	}
	for_each(v.begin(), v.end(), gruntPig);
	auto it = find(v.begin(), v.end(), 3); // To support 'auto', C++ 11 is needed.
	cout << "Found you! Pig: " << it->grunt() << endl;
	it = v.erase(it);
	cout << "You are the next! Pig: " << it->grunt() << endl;
}

int main(){
	test1();
	test2();
	return 0;
}
Output:
------------ Round One : Pig Pointers ------------
Pig: 1
Pig: 2
Pig: 3
Pig: 4
Pig: 5
Found you! Pig: 2
You are the next! Pig: 3
Here is Pig:2
Pig 2 died!
Pig 5 died!
Pig 4 died!
Pig 3 died!
Pig 1 died!
------------ Round Two : Pigs ------------
Pig 1 died!
Pig 1 died!
Pig 2 died!
Pig 1 died!
Pig 2 died!
Pig 3 died!
Pig 4 died!
Pig 1 died!
Pig 2 died!
Pig 3 died!
Pig 4 died!
Pig 5 died!
Pig: 1
Pig 1 died!
Pig: 2
Pig 2 died!
Pig: 3
Pig 3 died!
Pig: 4
Pig 4 died!
Pig: 5
Pig 5 died!
Pig 3 died!
Pig 3 died!
Pig 3 died!
Found you! Pig: 3
Pig 5 died!
You are the next! Pig: 4
Pig 1 died!
Pig 2 died!
Pig 4 died!
Pig 5 died!
Round One不難理解, 它說明erase的時候並沒有調用析構函數, 注意這是因爲我在Round One中向vector中存儲的是指針(Pointer), 而不是對象(Object), 因此沒有調用指針的析構函數.
參考: http://www.cplusplus.com/forum/general/63770/

Round Two就複雜了...未完待續.




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章