对vector<自定义类>使用std::find 和 std::find_if 算法
最后更新于:2022-04-01 06:44:35
##实战c++中的vector系列--对vector<自定义类>使用std::find 和 std::find_if 算法
之前博客讲了一些关于std::find和std::find_ if的一些用法,但是没有讲述对于vector中存储的是自定义的类,那么怎么样使用std::find和std::find_if进行查找呢?
先定义一个类:
~~~
class Item
{
private:
std::string m_ItemId;
int m_Price;
int m_Count;
public:
Item(std::string id, int price, int count):
m_ItemId(id), m_Count(count), m_Price(price){}
int getCount() const {
return m_Count;
}
std::string getItemId() const {
return m_ItemId;
}
int getPrice() const {
return m_Price;
}
bool operator==(const Item & obj2) const
{
if(this->getItemId().compare(obj2.getItemId()) == 0)
return true;
else
return false;
}
};
std::vector<Item> getItemList()
{
std::vector<Item> vecOfItems ;
vecOfItems.push_back(Item("D121",100,2));
vecOfItems.push_back(Item("D122",12,5));
vecOfItems.push_back(Item("D123",28,6));
vecOfItems.push_back(Item("D124",8,10));
vecOfItems.push_back(Item("D125",99,3));
return vecOfItems;
}
~~~
接下来就是使用std::find算法了:
~~~
int main()
{
std::vector<Item> vecOfItems = getItemList();
std::vector<Item>::iterator it;
it = std::find(vecOfItems.begin(), vecOfItems.end(), Item("D123", 99, 0));
if (it != vecOfItems.end())
std::cout << "Found with Price ::" << it->getPrice() << " Count :: " << it->getCount() << std::endl;
else
std::cout << "Item with ID :: D126 not Found" << std::endl;
return 0;
}
//输出:
Found with Price ::28 Count :: 6
~~~
但是如果不能使用==的情况下,我们就可以使用find_if解决问题了:
增加函数:
~~~
bool priceComparision(Item & obj, int y)
{
if(obj.getPrice() == y)
return true;
else
return false;
}
~~~
就是这样:
~~~
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<functional>
using namespace std;
class Item
{
private:
std::string m_ItemId;
int m_Price;
int m_Count;
public:
Item(std::string id, int price, int count) :
m_ItemId(id), m_Count(count), m_Price(price) {}
int getCount() const {
return m_Count;
}
std::string getItemId() const {
return m_ItemId;
}
int getPrice() const {
return m_Price;
}
bool operator==(const Item & obj2) const
{
if (this->getItemId().compare(obj2.getItemId()) == 0)
return true;
else
return false;
}
};
bool priceComparision(Item & obj, int y)
{
if (obj.getPrice() == y)
return true;
else
return false;
}
std::vector<Item> getItemList()
{
std::vector<Item> vecOfItems;
vecOfItems.push_back(Item("D121", 100, 2));
vecOfItems.push_back(Item("D122", 12, 5));
vecOfItems.push_back(Item("D123", 28, 6));
vecOfItems.push_back(Item("D124", 8, 10));
vecOfItems.push_back(Item("D125", 99, 3));
return vecOfItems;
}
int main()
{
std::vector<Item> vecOfItems = getItemList();
std::vector<Item>::iterator it;
it = std::find_if(vecOfItems.begin(), vecOfItems.end(), std::bind(priceComparision, std::placeholders::_1, 28));
if (it != vecOfItems.end())
std::cout << "Item Price ::" << it->getPrice() << " Count :: " << it->getCount() << std::endl;
else
std::cout << "Item not Found" << std::endl;
return 0;
}
~~~
最后还可以使用lambda表达式:
~~~
std::vector<Item> vecOfItems = getItemList();
std::vector<Item>::iterator it;
it = std::find_if(vecOfItems.begin(), vecOfItems.end(), [](Item const& obj){
return obj.getPrice() == 28;
} );
if(it != vecOfItems.end())
std::cout<<"Item Price ::"<<it->getPrice()<<" Count :: "<<it->getCount()<<std::endl;
else
std::cout<<"Item not Found"<<std::endl;
~~~
使用sort算法对vector<unique_ptr<string>>进行排序(sort函数“应输入 2 个参数,却提供了 3 个)
最后更新于:2022-04-01 06:44:33
##实战c++中的vector系列--使用sort算法对vector<unique_ptr<string>>进行排序(sort函数“应输入 2 个参数,却提供了 3 个)
之前博客写了对vector使用sort算法进行的排序,之前也写到过`vector<unique_ptr<string>>`的一些处理方法。
今天就写一下对`vector<unique_ptr<string>>`使用sort算法进行排序。
~~~
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<memory>
bool compare_int(int &lhs, int & rhs)
{
return lhs > rhs;
}
bool compare_first_letter(const std::unique_ptr<std::string > &lhs, const std::unique_ptr<std::string > & rhs)
{
return ((*lhs) < (*rhs));
}
bool compare_unique_ptr_int( std::unique_ptr<int > &lhs, std::unique_ptr<int > & rhs)
{
return *lhs < *rhs;
}
//bool compare_by_uniqptr(const unique_ptr<int>& a,
// const unique_ptr<int>& b) {
// return *a < *b;
//}
int main()
{
//sort vector<int>
std::vector<int> int_vector;
int_vector.push_back(5);
int_vector.push_back(4);
int_vector.push_back(3);
int_vector.push_back(6);
int_vector.push_back(9);
for (int i = 0; i < int_vector.size(); i++)
{
std::cout << int_vector[i] << " ";
}
std::cout << std::endl;
sort(int_vector.begin(), int_vector.end(), compare_int);
for (int i = 0; i < int_vector.size(); i++)
{
std::cout << (int_vector[i]) << " ";
}
std::cout << std::endl;
// sort vector<unique_ptr<string>>
std::vector<std::unique_ptr<std::string>> unique_ptr_string_vector;
std::unique_ptr<std::string> unique_ptr_string(new std::string("adr"));
unique_ptr_string_vector.push_back(std::move(unique_ptr_string));
std::unique_ptr<std::string> unique_ptr_string8(new std::string("abc"));
unique_ptr_string_vector.push_back(std::move(unique_ptr_string8));
std::unique_ptr<std::string> unique_ptr_string7(new std::string("abr"));
unique_ptr_string_vector.push_back(std::move(unique_ptr_string7));
std::unique_ptr<std::string> unique_ptr_string6(new std::string("aar"));
unique_ptr_string_vector.push_back(std::move(unique_ptr_string6));
std::unique_ptr<std::string> unique_ptr_string2(new std::string("ebr"));
unique_ptr_string_vector.push_back(std::move(unique_ptr_string2));
std::unique_ptr<std::string> unique_ptr_string3(new std::string("dbr"));
unique_ptr_string_vector.push_back(std::move(unique_ptr_string3));
std::unique_ptr<std::string> unique_ptr_string4(new std::string("cbr"));
unique_ptr_string_vector.push_back(std::move(unique_ptr_string4));
std::unique_ptr<std::string> unique_ptr_string5(new std::string("bbr"));
unique_ptr_string_vector.push_back(std::move(unique_ptr_string5));
for (int i = 0; i < unique_ptr_string_vector.size(); i++)
{
std::cout << *(unique_ptr_string_vector[i]) << " ";
}
std::cout << std::endl;
sort(unique_ptr_string_vector.begin(), unique_ptr_string_vector.end(), compare_first_letter);
for (int i = 0; i < unique_ptr_string_vector.size(); i++)
{
std::cout << *(unique_ptr_string_vector[i]) << " ";
}
std::cout << std::endl;
//sort vector<unique_ptr<int>>
std::vector<std::unique_ptr<int>> v;
std::unique_ptr<int> unique_ptr_int(new int(5));
v.push_back(std::move(unique_ptr_int));
std::unique_ptr<int> unique_ptr_int1(new int(4));
v.push_back(std::move(unique_ptr_int1));
std::unique_ptr<int> unique_ptr_int2(new int(3));
v.push_back(std::move(unique_ptr_int2));
std::unique_ptr<int> unique_ptr_int3(new int(6));
v.push_back(std::move(unique_ptr_int3));
std::unique_ptr<int> unique_ptr_int4(new int(9));
v.push_back(std::move(unique_ptr_int4));
for (int i = 0; i < v.size(); i++)
{
std::cout << *v[i] << " ";
}
std::cout << std::endl;
//sort(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()), compare_unique_ptr_int);
//for (auto i = v.begin(); i != v.end(); i++)
//{
// std::cout << **i << " ";
//}
//std::cout << std::endl;
sort(v.begin(), v.end(), compare_unique_ptr_int);
for (auto i = v.begin(); i != v.end(); i++)
{
std::cout << **i << " ";
}
std::cout << std::endl;
return 0;
}
//输出:
5 4 3 6 9
9 6 5 4 3
adr abc abr aar ebr dbr cbr bbr
aar abc abr adr bbr cbr dbr ebr
5 4 3 6 9
3 4 5 6 9
~~~
其实还很简单的,但是对于在类中使用sort算法进行排序,需要注意一些问题。
你很能会遇到这样的错误:
sort函数出错“应输入 2 个参数,却提供了 3 个。
在类中你写了比较函数:
~~~
bool compare_unique_ptr_int( std::unique_ptr<int > &lhs, std::unique_ptr<int > & rhs)
{
return *lhs < *rhs;
}
~~~
然后在类的某个成员函数中,使用了sort方法进行排序,第三个参数使用compare_unique_ptr_int函数,这个时候就会出现上面所说的错误。
但是如何改进呢?
方法有两种:
方法一:把compare_unique_ptr_int函数改为静态方法:
~~~
static bool compare_unique_ptr_int( std::unique_ptr<int > &lhs, std::unique_ptr<int > & rhs)
{
return *lhs < *rhs;
}
sort(v.begin(), v.end(), compare_unique_ptr_int);
~~~
方法二:使用lambda表达式进行
~~~
sort(v.begin(), v.end(), [](std::unique_ptr<int > &lhs, std::unique_ptr<int > & rhs)(){return *lhs < *rhs;});
~~~
这样就大功告成了!!!
vector应用之STL的find、find_if、find_end、find_first_of、find_if_not(C++11)
最后更新于:2022-04-01 06:44:31
##实战c++中的vector系列--vector应用之STL的find、find_if、find_end、find_first_of、find_if_not(C++11)
使用vector容器,即避免不了进行查找,所以今天就罗列一些stl的find算法应用于vector中。
**find()**
Returns an iterator to the first element in the range [first,last) that compares equal to val. If no such element is found, the function returns last.
~~~
#include <iostream> // std::cout
#include <algorithm> // std::find
#include <vector> // std::vector
int main () {
// using std::find with array and pointer:
int myints[] = { 10, 20, 30, 40 };
int * p;
p = std::find (myints, myints+4, 30);
if (p != myints+4)
std::cout << "Element found in myints: " << *p << '\n';
else
std::cout << "Element not found in myints\n";
// using std::find with vector and iterator:
std::vector<int> myvector (myints,myints+4);
std::vector<int>::iterator it;
it = find (myvector.begin(), myvector.end(), 30);
if (it != myvector.end())
std::cout << "Element found in myvector: " << *it << '\n';
else
std::cout << "Element not found in myvector\n";
return 0;
}
//
30
30
~~~
**find_end()**
Searches the range [first1,last1) for the last occurrence of the sequence defined by [first2,last2), and returns an iterator to its first element, or last1 if no occurrences are found.
~~~
#include <iostream> // std::cout
#include <algorithm> // std::find_end
#include <vector> // std::vector
bool myfunction (int i, int j) {
return (i==j);
}
int main () {
int myints[] = {1,2,3,4,5,1,2,3,4,5};
std::vector<int> haystack (myints,myints+10);
int needle1[] = {1,2,3};
// using default comparison:
std::vector<int>::iterator it;
it = std::find_end (haystack.begin(), haystack.end(), needle1, needle1+3);
if (it!=haystack.end())
std::cout << "needle1 last found at position " << (it-haystack.begin()) << '\n';
int needle2[] = {4,5,1};
// using predicate comparison:
it = std::find_end (haystack.begin(), haystack.end(), needle2, needle2+3, myfunction);
if (it!=haystack.end())
std::cout << "needle2 last found at position " << (it-haystack.begin()) << '\n';
return 0;
}
//输出:
5
3
~~~
**find_if()**
Returns an iterator to the first element in the range [first,last) for which pred returns true. If no such element is found, the function returns last.
~~~
#include <iostream> // std::cout
#include <algorithm> // std::find_if
#include <vector> // std::vector
bool IsOdd (int i) {
return ((i%2)==1);
}
int main () {
std::vector<int> myvector;
myvector.push_back(10);
myvector.push_back(25);
myvector.push_back(40);
myvector.push_back(55);
std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
std::cout << "The first odd value is " << *it << '\n';
return 0;
}
//输出:
25
~~~
顺便说一句可以使用lambda表达式代替IsOdd函数,使得更加简洁。
**find_first_of()**
Returns an iterator to the first element in the range [first1,last1) that matches any of the elements in [first2,last2). If no such element is found, the function returns last1.
~~~
#include <iostream> // std::cout
#include <algorithm> // std::find_first_of
#include <vector> // std::vector
#include <cctype> // std::tolower
bool comp_case_insensitive (char c1, char c2) {
return (std::tolower(c1)==std::tolower(c2));
}
int main () {
int mychars[] = {'a','b','c','A','B','C'};
std::vector<char> haystack (mychars,mychars+6);
std::vector<char>::iterator it;
int needle[] = {'A','B','C'};
// using default comparison:
it = find_first_of (haystack.begin(), haystack.end(), needle, needle+3);
if (it!=haystack.end())
std::cout << "The first match is: " << *it << '\n';
// using predicate comparison:
it = find_first_of (haystack.begin(), haystack.end(),
needle, needle+3, comp_case_insensitive);
if (it!=haystack.end())
std::cout << "The first match is: " << *it << '\n';
return 0;
}
输出:
A
a
~~~
**find_if_not()**
最后出厂这个 我们应该重视一些 是C++11才有的方法。个人觉得用处很多,看看官方的描述:
Returns an iterator to the first element in the range [first,last) for which pred returns false. If no such element is found, the function returns last.
例子:
~~~
#include <iostream> // std::cout
#include <algorithm> // std::find_if_not
#include <array> // std::array
int main () {
std::array<int,5> foo = {1,2,3,4,5};
std::array<int,5>::iterator it =
std::find_if_not (foo.begin(), foo.end(), [](int i){return i%2;} );
std::cout << "The first even value is " << *it << '\n';
return 0;
}
//输出:
2
~~~
最后 再来一个程序:
~~~
#include <vector>
#include <string>
#include <algorithm>
struct value_t
{
int a;
int b;
};
class vector_finder
{
public:
vector_finder(const int a) :m_i_a(a) {}
bool operator ()(const std::vector<struct value_t>::value_type &value)
{
return value.a == m_i_a;
}
private:
int m_i_a;
};
int main()
{
std::vector<struct value_t> my_vector;
struct value_t my_value;
my_value.a = 11; my_value.b = 1000;
my_vector.push_back(my_value);
my_value.a = 12; my_value.b = 1000;
my_vector.push_back(my_value);
my_value.a = 13; my_value.b = 1000;
my_vector.push_back(my_value);
my_value.a = 14; my_value.b = 1000;
my_vector.push_back(my_value);
std::vector<struct value_t>::iterator it = my_vector.end();
it = std::find_if(my_vector.begin(), my_vector.end(), vector_finder(13));
if (it == my_vector.end())
printf("not found\n");
else
printf("found value.a:%d value.b:%d\n", it->a, it->b);
return 0;
}
~~~
最后来一个实战中用到的,`vector<string>`中的string的首字母按照字母表进行排序:
~~~
#include <iostream> // std::cout
#include <algorithm> // std::stable_sort
#include <vector> // std::vector
#include <string>
static char ch = 'a';
bool myfunction(const std::string& lhs, const std::string& rhs)
{
return lhs < rhs;
}
bool myfunction2(const std::string& lhs)
{
return lhs[0] == ch;
}
int main() {
std::vector<std::string> myvector;
myvector.push_back("wo");
myvector.push_back("wi");
myvector.push_back("wa");
myvector.push_back("ao");
myvector.push_back("bo");
myvector.push_back("ae");
myvector.push_back("bv");
myvector.push_back("cd");
myvector.push_back("ef");
myvector.push_back("gd");
myvector.push_back("ww");
myvector.push_back("cd");
myvector.push_back("at");
myvector.push_back("bt");
myvector.push_back("ct");
myvector.push_back("dt");
myvector.push_back("et");
myvector.push_back("ft");
myvector.push_back("gt");
myvector.push_back("ht");
myvector.push_back("it");
myvector.push_back("jt");
myvector.push_back("kt");
myvector.push_back("lt");
myvector.push_back("mt");
myvector.push_back("nt");
myvector.push_back("ot");
myvector.push_back("pt");
myvector.push_back("qt");
myvector.push_back("rt");
myvector.push_back("st");
myvector.push_back("tt");
myvector.push_back("ut");
myvector.push_back("vt");
myvector.push_back("wt");
myvector.push_back("xt");
//myvector.push_back("yt");
myvector.push_back("zt");
myvector.push_back("qt");
myvector.push_back("et");
myvector.push_back("ee");
std::stable_sort(myvector.begin(), myvector.end(), myfunction);
for (std::string &s : myvector)
std::cout << s << " ";
std::cout << std::endl;
std::cout << "===============" << std::endl;
for (int i = 1;i < 27; i++)
{
auto it_begin = std::find_if(myvector.begin(), myvector.end(), myfunction2);
auto it_end = std::find_if_not(it_begin, myvector.end(), myfunction2);
for (auto i = it_begin; i != it_end; i++)
{
std::cout << *i << " ";
}
std::cout << std::endl;
ch++;
}
return 0;
}
//输出:
ae ao at bo bt bv cd cd ct dt ee ef et et ft gd gt ht it jt kt lt mt nt ot pt qt qt rt st tt ut vt wa wi wo wt ww xt zt
===============
ae ao at
bo bt bv
cd cd ct
dt
ee ef et et
ft
gd gt
ht
it
jt
kt
lt
mt
nt
ot
pt
qt qt
rt
st
tt
ut
vt
wa wi wo wt ww
xt
zt
~~~
使用sort算法对vector进行排序(对vector<string>排序、使用稳定的排序std::stable_sort())
最后更新于:2022-04-01 06:44:28
##实战c++中的vector系列--使用sort算法对vector进行排序(对vector<string>排序、使用稳定的排序std::stable_sort())
写了挺多关于vector的操作了,正好工作中遇到对vector进行排序的问题,这里就讨论一下。
直接使用sort算法,那就先了解一下:
~~~
template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);
template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
~~~
Sorts the elements in the range [first,last) into ascending order.
The elements are compared using operator< for the first version, and comp for the second.
Equivalent elements are not guaranteed to keep their original relative order (see stable_sort).
也就是所说的不稳定排序。
直接上代码:
~~~
#include <iostream> // std::cout
#include <algorithm> // std::sort
#include <vector> // std::vector
#include <string>
bool myfunction(int i, int j) { return (i<j); }
struct myclass {
bool operator() (int i, int j) { return (i<j); }
} myobject;
int main() {
int myints[] = { 32,71,12,45,26,80,53,33 };
std::vector<int> myvector(myints, myints + 8);// 32 71 12 45 26 80 53 33
// using default comparison (operator <)
std::sort(myvector.begin(), myvector.begin() + 4); //(12 32 45 71)26 80 53 33
// using function as comp
std::sort(myvector.begin() + 4, myvector.end(), myfunction); // 12 32 45 71(26 33 53 80)
// using object as comp
std::sort(myvector.begin(), myvector.end(), myobject); //(12 26 32 33 45 53 71 80)
// print out content:
std::cout << "myvector contains:";
for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
// Sorting the string vector
std::vector<std::string> stringVec = { "John", "Bob", "Joe", "Zack", "Randy" };
sort(stringVec.begin(), stringVec.end());
for (std::string &s : stringVec)
std::cout << s << " ";
return 0;
}
//输出:
myvector contains: 12 26 32 33 45 53 71 80
Bob Joe John Randy Zack
~~~
这个时候可以使用std::stable_sort()来实现稳定的排序了:
Sorts the elements in the range [first,last) into ascending order, like sort, but stable_sort preserves the relative order of the elements with equivalent values.
~~~
#include <iostream> // std::cout
#include <algorithm> // std::stable_sort
#include <vector> // std::vector
bool compare_as_ints(double i, double j)
{
return (int(i)<int(j));
}
int main() {
double mydoubles[] = { 3.14, 1.41, 2.72, 4.67, 1.73, 1.32, 1.62, 2.58 };
std::vector<double> myvector;
myvector.assign(mydoubles, mydoubles + 8);
std::cout << "using default comparison:";
std::stable_sort(myvector.begin(), myvector.end());
for (std::vector<double>::iterator it = myvector.begin(); it != myvector.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
myvector.assign(mydoubles, mydoubles + 8);
std::cout << "using 'compare_as_ints' :";
std::stable_sort(myvector.begin(), myvector.end(), compare_as_ints);
for (std::vector<double>::iterator it = myvector.begin(); it != myvector.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
//输出:
using default comparison: 1.32 1.41 1.62 1.73 2.58 2.72 3.14 4.67
using 'compare_as_ints' : 1.41 1.73 1.32 1.62 2.72 2.58 3.14 4.67
~~~
vector的遍历(stl算法、vector迭代器(不要在循环中判断不等于end())、operator[])
最后更新于:2022-04-01 06:44:26
## 实战c++中的vector系列--vector的遍历(stl算法、vector迭代器(不要在循环中判断不等于end())、operator[])
遍历一个vector容器有很多种方法,使用起来也是仁者见仁。
通过索引遍历:
~~~
for (i = 0; i<v.size(); i++)
{
cout << v[i] << " ";
}
~~~
迭代器遍历:
~~~
for (vInt::const_iterator iter = v.begin(); iter != v.end();iter++)
{
cout << *iter << " ";
}
~~~
算法遍历:
~~~
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
~~~
很多书上推荐的是使用算法进行遍历。写了一个简单的程序对上面的三种方法进行了比较:
~~~
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
#include<time.h>
#include<windows.h>
using namespace std;
typedef vector<int> vInt;
void print_vec_operator(const vInt & v)//方法一,采用下标访问
{
int i;
for (i = 0; i<v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
}
void print_vec_iterator(const vInt &v)//方法二,采用迭代器访问
{
for (vInt::const_iterator iter = v.begin(); iter != v.end();iter++)
{
cout << *iter << " ";
}
cout << endl;
}
void print_vec_algorithm(const vInt &v)//方法三,将容器的内容复制到cout绑定的迭代器
{
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
}
int main()
{
vInt v;
int i;
for (i = 0; i<100000; i++)
{
v.push_back(i);
}
int start_time_print_vec1 = GetTickCount();
print_vec_operator(v);
int end_time_print_vec1 = GetTickCount();
int start_time_print_vec2 = GetTickCount();
print_vec_iterator(v);
int end_time_print_vec2 = GetTickCount();
int start_time_print_vec3 = GetTickCount();
print_vec_algorithm(v);
int end_time_print_vec3 = GetTickCount();
std::cout << (end_time_print_vec1 - start_time_print_vec1) << endl;
std::cout << (end_time_print_vec2 - start_time_print_vec2) << endl;
std::cout << (end_time_print_vec3 - start_time_print_vec3) << endl;
return 0;
}
~~~
当vector初始化10000个元素时,三种方法的效率不相上下,运行几次时间相差无几:
//输出:
//1718 operator[]
//1735 iterator
//1797 algorithm
但是当把veector初始化100000的时候,三种方法的效率就有了较大的差距:
//输出:
//20016 operator[]
//32172 iterator
//62468 algorithm
再写一个vector里放一个类:
~~~
#include<iostream>
#include<vector>
#include<iterator>
#include <algorithm>
#include <functional>
#include<windows.h>
class AAA
{
public:
void MakeFull2()
{
}
};
int main()
{
int nCount = 1000000;
std::vector< AAA* > vAAA;
vAAA.resize(nCount);
for (int i = 0; i < nCount; ++i)
{
vAAA[i] = new AAA;
}
// 时间
int start, end;
// 测试成员函数调用(std::vector下标访问方式)
start = GetTickCount();
size_t count = vAAA.size();
for (size_t i = 0; i < count; ++i)
vAAA[i]->MakeFull2();
end = GetTickCount();
std::cout << end - start << std::endl;
// 测试成员函数调用(STL算法方式)
start = GetTickCount();
std::for_each(vAAA.begin(), vAAA.end(),
std::mem_fun<void, AAA>(&AAA::MakeFull2));
end = GetTickCount();
std::cout << end - start << std::endl;
// 测试成员函数调用(STL迭代器方式)
start = GetTickCount();
std::vector< AAA* >::iterator itr_end = vAAA.end();
for (std::vector< AAA* >::iterator itr = vAAA.begin(); itr != itr_end; ++itr)
(*itr)->MakeFull2();
end = GetTickCount();
std::cout << end - start << std::endl;
// 测试成员函数调用(STL迭代器方式)
start = GetTickCount();
for (std::vector< AAA* >::iterator itr = vAAA.begin(); itr != vAAA.end(); ++itr)
(*itr)->MakeFull2();
end = GetTickCount();
std::cout << end - start << std::endl;
return 0;
}
//输出:
//313 oprator[]
//62 algorithm
//422 iterator
//922 iterator
~~~
再运行一次,结果为:
//296
//63
//594
//1672
这个时候使用algorithm+functional进行遍历效率最高。
个人觉得下标索引的方式总是会效率高于迭代器方式。
下面分析一下两种迭代器方式,为何相差不小呢:
这就要看一下std::vector::end()的原型了:
~~~
iterator end() _NOEXCEPT
{ // return iterator for end of mutable sequence
return (iterator(this->_Mylast(), &this->_Get_data()));
}
~~~
就是每次判断itr != vAAA.end()的时候,都要进行重新构造一个迭代器并进行返回,这样当然降低的效率。
vector的一些异常
最后更新于:2022-04-01 06:44:24
##实战c++中的vector系列--vector的一些异常
今天就写一写vector的一些异常,可以捕捉的异常。
**out_of_range**
相当于数组的越界了。vector会自动增大容量,但是如果索引超出了当前的size,就会引发异常。
~~~
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int>v(4);
std::cout << v[0] << std::endl;
std::cout << v[1] << std::endl;
std::cout << v[2] << std::endl;
std::cout << v[3] << std::endl;
std::cout << v[4] << std::endl;//越界
return 0;
}
~~~
除了使用索引外,还有使用vector.at()时发生越界:
~~~
#include <iostream> // std::cerr
#include <stdexcept> // std::out_of_range
#include <vector> // std::vector
int main (void) {
std::vector<int> myvector(10);
try {
myvector.at(20)=100; // vector::at throws an out-of-range
}
catch (const std::out_of_range& oor) {
std::cerr << "Out of Range error: " << oor.what() << '\n';
}
return 0;
}
~~~
**std::length_error**
在使用vector的时候,很少会引发std::length_error异常,但是如果疏忽大意写这样的代码:
~~~
#include <iostream> // std::cerr
#include <stdexcept> // std::length_error
#include <vector> // std::vector
int main (void) {
try {
// vector throws a length_error if resized above max_size
std::vector<int> myvector;
myvector.resize(myvector.max_size()+1);
}
catch (const std::length_error& le) {
std::cerr << "Length error: " << le.what() << '\n';
}
return 0;
}
~~~
vector* pData;
emplace_back造成的引用失效
最后更新于:2022-04-01 06:44:21
##实战c++中的vector系列--emplace_back造成的引用失效
上篇将了对于struct或是class为何emplace_back要优越于push_back,但是还有一些细节没有提及。今天就谈一谈emplace_back造成的引用失效。
直接撸代码了:
~~~
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<int> ivec;
ivec.emplace_back(1);
ivec.emplace_back(ivec.back());
for (auto it = ivec.begin(); it != ivec.end(); ++it)
cout << *it << " ";
return 0;
}
//输出:
1 -572662307
~~~
尝试1:不直接给emplace_back传递ivec.back():
~~~
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<int> ivec;
ivec.emplace_back(1);
auto &it = ivec.back();
ivec.emplace_back(it);
for (auto it = ivec.begin(); it != ivec.end(); ++it)
cout << *it << " ";
return 0;
}
输出:
1 -572662307
~~~
尝试2:不给emplace_back传递引用:
~~~
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<int> ivec;
ivec.emplace_back(1);
auto it = ivec.back();
ivec.emplace_back(it);
for (auto it = ivec.begin(); it != ivec.end(); ++it)
cout << *it << " ";
return 0;
}
输出:
1 1
~~~
我们如愿以偿,这时候应该可以得到结论了,ivec.back()返回的是引用,但是这个引用失效了,所以才会输出不正确;我们之前也提到过,重新分配内存会造成迭代器的失效,这里是造成了引用的失效。
再回头看看emplace_back的描述:
if a reallocation happens, all iterators, pointers and references related to this container are invalidated.
Otherwise, only the end iterator is invalidated, and all other iterators, pointers and references to elements are guaranteed to keep referring to the same elements they were referring to before the call.
进一步。
尝试3:避免emplace_back引起重新分配内存:
~~~
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<int> ivec;
ivec.reserve(4);
ivec.emplace_back(1);
ivec.emplace_back(ivec.back());
for (auto it = ivec.begin(); it != ivec.end(); ++it)
cout << *it << " ";
return 0;
}
输出:
1 1
~~~
但是这个时候问题来了,如果不使用emplace_back而改用push_back呢?
~~~
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<int> ivec;
ivec.push_back(1);
ivec.push_back(ivec.back());
ivec.push_back(ivec.back());
ivec.push_back(ivec.back());
for (auto it = ivec.begin(); it != ivec.end(); ++it)
cout << *it << " ";
return 0;
}
//输出:
1 1 1 1
~~~
为什么使用push_back就不失效呢?
知道emplace_back为何优于push_back吗?
最后更新于:2022-04-01 06:44:19
##实战c++中的vector系列--知道emplace_back为何优于push_back吗?
上一篇博客说道vector中放入struct,我们先构造一个struct对象,再push_back。
那段代码中,之所以不能使用emplace_back,就是因为我们定义的struct没有显示的构造函数。
emplace和解?
放列的意思。
这次我们不把struct当做vector的元素了,我们把一个class当做vector的元素,写下代码:
~~~
#include <iostream>
#include <vector>
#include<string>
using namespace std;
class CText {
private:
string str;
public:
text(string s) :str(s) {
}
void show()const {
cout << str << endl;
}
};
int main()
{
vector<CText > vi;
vi.emplace_back("hey");
vi.front().show();
vi.push_back("girl");//错误
vi.back().show();
return 0;
}
~~~
其中vi.push_back(“girl”);这条语句错误,VS2015报错为:
~~~
error C2664: “void std::vector<text,std::allocator<_Ty>>::push_back(const text &)”: 无法将参数 1 从“const char [5]”转换为“text &&”
~~~
但此时我们稍作修改:
把 vi.push_back(“girl”) 改为
vi.push_back(CText(“girl”));
问题就解决了。。
简而言之,就是empace_back与push_back相比,替我们省去了调用CText进行构造。
**emplace_back**
添加一个新元素到结束的容器。该元件是构成在就地,即没有复制或移动操作进行。
inserts a new element at the end of the vector, right after its current last element. This new element is constructed in place using args as the arguments for its constructor.
This effectively increases the container size by one, which causes an automatic reallocation of the allocated storage space if -and only if- the new vector size surpasses the current vector capacity.
The element is constructed in-place by calling allocator_traits::construct with args forwarded.
A similar member function exists, push_back, which either copies or moves an existing object into the container.
写到这里,你应该明白emplace_back如何是也了吧。
最后再来一段代码,涉及到使用右值引用和std::move的:
~~~
#include <vector>
#include <string>
#include <iostream>
struct President
{
std::string name;
std::string country;
int year;
President(std::string && p_name, std::string && p_country, int p_year)
: name(std::move(p_name)), country(std::move(p_country)), year(p_year)
{
std::cout << "I am being constructed.\n";
}
President(President&& other)
: name(std::move(other.name)), country(std::move(other.country)), year(other.year)
{
std::cout << "I am being moved.\n";
}
President& operator=(const President& other) = default;
};
int main()
{
std::vector<President> elections;
std::cout << "emplace_back:\n";
elections.emplace_back("Nelson Mandela", "South Africa", 1994);
std::vector<President> reElections;
std::cout << "\npush_back:\n";
reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));
std::cout << "\nContents:\n";
for (President const& president : elections) {
std::cout << president.name << " was elected president of "
<< president.country << " in " << president.year << ".\n";
}
for (President const& president : reElections) {
std::cout << president.name << " was re-elected president of "
<< president.country << " in " << president.year << ".\n";
}
}
//输出:
emplace_back:
I am being constructed.
push_back:
I am being constructed.
I am being moved.
Contents:
Nelson Mandela was elected president of South Africa in 1994.
Franklin Delano Roosevelt was re-elected president of the USA in 1936.
~~~
creating vector of local structure、vector of structs initialization
最后更新于:2022-04-01 06:44:17
##实战c++中的vector系列--creating vector of local structure、vector of structs initialization
之前一直没有使用过`vector<struct>,现在就写一个简短的代码:
`
~~~
#include <vector>
#include <iostream>
int main() {
struct st { int a; };
std::vector<st> v;
v.resize(4);
for (std::vector<st>::size_type i = 0; i < v.size(); i++) {
v.operator[](i).a = i + 1; // v[i].a = i+1;
}
for (int i = 0; i < v.size(); i++)
{
std::cout << v[i].a << std::endl;
}
}
~~~
用VS2015编译成功,运行结果:
1
2
3
4
但是,这是C++11之后才允许的,之前编译器并不允许你写这样的语法,不允许vector容器内放local structure。
更进一步,如果struct里面有好几个字段呢?
~~~
#include<iostream>
#include<string>
#include<vector>
using namespace std;
struct subject {
string name;
int marks;
int credits;
};
int main() {
vector<subject> sub;
//Push back new subject created with default constructor.
sub.push_back(subject());
//Vector now has 1 element @ index 0, so modify it.
sub[0].name = "english";
//Add a new element if you want another:
sub.push_back(subject());
//Modify its name and marks.
sub[1].name = "math";
sub[1].marks = 90;
sub.push_back({ "Sport", 70, 0 });
sub.resize(8);
//sub.emplace_back("Sport", 70, 0 );
for (int i = 0; i < sub.size(); i++)
{
std::cout << sub[i].name << std::endl;
}
}
~~~
但是上面的做法不好,我们应该先构造对象,后进行push_back 也许更加明智。
subject subObj;
subObj.name = s1;
sub.push_back(subObj);
这个就牵扯到一个问题,为什么不使用emplace_back来替代push_back呢,这也是我们接下来讨论 话题。
vector<unique_ptr<>>赋值给vector<unique_ptr<>>
最后更新于:2022-04-01 06:44:15
##实战c++中的vector系列--vector<unique_ptr<>>赋值给vector<unique_ptr<>>
之前博客讲到 vector可以使用insert方法,将一个vector copy到另一个vector的后面。
之前的博客也讲到过,如果vector容器内部放的是unique_ptr是需要进行所有权转移的。
现在就来八一八如何`vector<unique_ptr<>> insert to vector<unique_ptr<>>`
如果常规的vector,我们就可以这么使用insert:
~~~
// inserting into a vector
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (3,100);//100 100 100
std::vector<int>::iterator it;
it = myvector.begin();
it = myvector.insert ( it , 200 );//200 100 100 100
myvector.insert (it,2,300);//300 300 200 100 100 100
// "it" no longer valid, get a new one:
it = myvector.begin();
std::vector<int> anothervector (2,400);
myvector.insert (it+2,anothervector.begin(),anothervector.end());
//now, 300 300 400 400 200 100 100 100
int myarray [] = { 501,502,503 };
myvector.insert (myvector.begin(), myarray, myarray+3);
std::cout << "myvector contains:";
for (it=myvector.begin(); it<myvector.end(); it++)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
//输出:
501 502 503 300 300 400 400 200 100 100 100
~~~
但是对于vector内的unique point来说,就不能简单的使用普通迭代器了:需要使用对迭代器就行std::make_move_iterator操作:
看下英文描述最可靠:
A move_iterator is an iterator adaptor that adapts an iterator (it) so that dereferencing it produces rvalue references (as if std::move was applied), while all other operations behave the same.
就跟我们之前用到的std::move作用是一样一样的~
看看使用例子:
~~~
#include <iostream> // std::cout
#include <iterator> // std::make_move_iterator
#include <vector> // std::vector
#include <string> // std::string
#include <algorithm> // std::copy
int main () {
std::vector<std::string> foo (3);
std::vector<std::string> bar {"one","two","three"};
std::copy ( make_move_iterator(bar.begin()),
make_move_iterator(bar.end()),
foo.begin() );
// bar now contains unspecified values; clear it:
bar.clear();
std::cout << "foo:";
for (std::string& x : foo) std::cout << ' ' << x;
std::cout << '\n';
return 0;
}
//输出:
foo: one two three
~~~
接下来就是我们的使用了,简单了吧:
~~~
#include<iostream>
#include<vector>
#include <memory>
using namespace std;
void display_vector(vector<unique_ptr<int>> &vec);
int main()
{
vector<unique_ptr<int>> vec;
unique_ptr<int> s1(new int(1));
unique_ptr<int> s2(new int(2));
unique_ptr<int> s3(new int(3));
unique_ptr<int> s4(new int(4));
vec.push_back(std::move(s1));
vec.push_back(std::move(s2));
vec.push_back(std::move(s3));
vec.push_back(std::move(s4));
unique_ptr<int> s5(new int(5));
vector<unique_ptr<int>> des_vec;
des_vec.push_back(std::move(s5));
des_vec.insert(des_vec.end(), std::make_move_iterator(vec.begin()), std::make_move_iterator(vec.end()));
display_vector(des_vec);
cout << "now, des_vec size: " << des_vec.size() << endl;
cout << "now, vec size: " << vec.size() << endl;
return 0;
}
void display_vector(vector<unique_ptr<int>> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << **it << endl;
}
//输出结果:
5
1
2
3
4
now, des_vec size: 5
now, vec size: 4
~~~
vector<unique_ptr<>>作为函数的参数
最后更新于:2022-04-01 06:44:12
##实战c++中的vector系列--vector<unique_ptr<>>作为函数的参数
现在就讨论一下,把vector作为函数的参数进行传递。
也是直接上一段代码:
~~~
#include<iostream>
#include<vector>
#include <memory>
using namespace std;
void display_vector(vector<unique_ptr<int>> vec);
int main()
{
vector<unique_ptr<int>> vec;
unique_ptr<int> s1(new int(1));
unique_ptr<int> s2(new int(2));
unique_ptr<int> s3(new int(3));
unique_ptr<int> s4(new int(4));
vec.push_back(std::move(s1));
vec.push_back(std::move(s2));
vec.push_back(std::move(s3));
vec.push_back(std::move(s4));
display_vector(vec);//还是所有权的问题
return 0;
}
void display_vector(vector<unique_ptr<int>> vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << **it << endl;
}
}
~~~
这个时候给display_vector传递std::move(vec)作为参数,并看一下调用display_vector函数后,vec变成了什么呢?
~~~
#include<iostream>
#include<vector>
#include <memory>
using namespace std;
void display_vector(vector<unique_ptr<int>> vec);
int main()
{
vector<unique_ptr<int>> vec;
unique_ptr<int> s1(new int(1));
unique_ptr<int> s2(new int(2));
unique_ptr<int> s3(new int(3));
unique_ptr<int> s4(new int(4));
vec.push_back(std::move(s1));
vec.push_back(std::move(s2));
vec.push_back(std::move(s3));
vec.push_back(std::move(s4));
display_vector(std::move(vec));
cout << "now, vec size:" << vec.size() << endl;
return 0;
}
void display_vector(vector<unique_ptr<int>> vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << **it << endl;
}
}
//输出:
1
2
3
4
now, vec size:0
~~~
传统的想法,我们传递的是值,而非引用,那为什么会影响vec呢,还是所有权转移问题。
那么我们如何不改变vec呢?
只要按引用、或是const引用传递即可,就不涉及到所有权的转移问题:
~~~
#include<iostream>
#include<vector>
#include <memory>
using namespace std;
void display_vector(vector<unique_ptr<int>> &vec);
int main()
{
vector<unique_ptr<int>> vec;
unique_ptr<int> s1(new int(1));
unique_ptr<int> s2(new int(2));
unique_ptr<int> s3(new int(3));
unique_ptr<int> s4(new int(4));
vec.push_back(std::move(s1));
vec.push_back(std::move(s2));
vec.push_back(std::move(s3));
vec.push_back(std::move(s4));
display_vector(vec);
cout << "now, vec size:" << vec.size() << endl;
return 0;
}
void display_vector(vector<unique_ptr<int>> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << **it << endl;
}
}
//输出:
1
2
3
4
now, vec size:4
~~~
vector<unique_ptr<>>初始化(所有权转移)
最后更新于:2022-04-01 06:44:10
##实战c++中的vector系列--vector<unique_ptr<>>初始化(所有权转移)
C++11为我们提供了智能指针,给我们带来了很多便利的地方。
那么如果把unique_ptr作为vector容器的元素呢?
形式如出一辙:`vector<unique_ptr<int> > vec;`
但是怎么给vec添加元素呢?
看下面:
~~~
#include<iostream>
#include<vector>
#include <memory>
using namespace std;
int main()
{
vector<unique_ptr<int>> vec;
vec.push_back(1);//错误
return 0;
}
~~~
那么先定义一个unique_ptr,再进行push_back():
~~~
#include<iostream>
#include<vector>
#include <memory>
using namespace std;
int main()
{
vector<unique_ptr<int>> vec;
unique_ptr<int> sp(new int(126));
vec.push_back(sp);//尝试引用已删除的函数
return 0;
}
~~~
这就是unique智能指针的所有权问题,这个时候就需要使用std::move:
~~~
#include<iostream>
#include<vector>
#include <memory>
using namespace std;
int main()
{
vector<unique_ptr<int>> vec;
unique_ptr<int> sp(new int(126));
//vec.push_back(1);
vec.push_back(std::move(sp));//尝试引用已删除的函数
cout << *vec[0]<< endl; // 输出126
//cout << *sp << endl;
return 0;
}
~~~
但是此时,上面代码的sp编程了什么呢? 使用*取值看一下,结果程序崩溃,原因何在?
就是此时sp已经释放,所有权转移了!
可怕的迭代器失效之二(删除vector中元素)
最后更新于:2022-04-01 06:44:08
##实战c++中的vector系列--可怕的迭代器失效之二(删除vector中元素)
有了上一篇博客《[实战c++中的vector系列–可怕的迭代器失效(vector重新申请内存)](http://blog.csdn.net/wangshubo1989/article/details/50334297 "迭代器失效")》的基础,这里的内容就显得简单了。
直接撸代码:
~~~
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
std::vector<int>::iterator iter1 = v.begin() + 2;
v.erase(v.begin() + 1);
int n = *iter1;
return 0;
}
~~~
erase后,迭代器失效了。
vector迭代器的几种失效的情况:
1.当插入(push_back)一个元素后,end操作返回的迭代器肯定失效。
2.当插入(push_back)一个元素后,capacity返回值与没有插入元素之前相比有改变,则需要重新加载整个容器,此时first和end操作返回的迭代器都会失效。
3.当进行删除操作(erase,pop_back)后,指向删除点的迭代器全部失效;指向删除点后面的元素的迭代器也将全部失效。
可怕的迭代器失效(vector重新申请内存)
最后更新于:2022-04-01 06:44:05
##实战c++中的vector系列--可怕的迭代器失效(vector重新申请内存)
vector给我们提供了很多的方便,但是偶尔也会有陷阱。当不注意的时候,就掉入其中。说到底,还是对vector的机制不够彻底掌握。
很轻松的写下这段代码:
~~~
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v;
v.push_back(1);
std::vector<int>::iterator iter1 = v.begin();
v.push_back(1);
int n = *iter1;//shit
cout << n << endl;
return 0;
}
~~~
上面的代码运行时崩溃,就是因为迭代器iter1在vector push_back新值后失效了。切记!
但是为什么会失效?
如果我先预先resize足够大,那么会如何呢?
~~~
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v;
v.resize(4);
v.push_back(1);
std::vector<int>::iterator iter1 = v.begin();
v.push_back(1);
int n = *iter1;
cout << n << endl;
return 0;
}
~~~
上面的代码正常运行,因为之前resize了足够的空间,即迭代器不会失效。
我们就已给vector push_back两个元素为例。resize(1), resize(2), resize(3)程序还是会崩溃。还是容量不足,导致vector重新分配内存,而导致迭代器失效。
之前讲过了resize与reserve的区别,那么上面的代码如果使用reserve呢?
~~~
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v;
v.reserve(2);
v.push_back(0);
std::vector<int>::iterator iter1 = v.begin();
v.push_back(1);
int n = *iter1;
cout << n << endl;
return 0;
}
~~~
还是以push_back两个元素为例,reserve(1)还是会导致崩溃,还是造成迭代器的失效。
接下来的问题就是vector的内存机制,当容量不够时,会申请多少内存?
还是写个程序看看:
~~~
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v;
for (int i = 1; i < 100; i++)
{
cout << "capacity:" << v.capacity() << ", " << "size" << v.size() << endl;
v.push_back(i);
}
return 0;
}
//输出:
capacity:0, size0
capacity:1, size1
capacity:2, size2
capacity:3, size3
capacity:4, size4
capacity:6, size5
capacity:6, size6
capacity:9, size7
capacity:9, size8
capacity:9, size9
capacity:13, size10
capacity:13, size11
capacity:13, size12
capacity:13, size13
capacity:19, size14
capacity:19, size15
capacity:19, size16
capacity:19, size17
capacity:19, size18
capacity:19, size19
capacity:28, size20
capacity:28, size21
capacity:28, size22
capacity:28, size23
capacity:28, size24
capacity:28, size25
capacity:28, size26
capacity:28, size27
capacity:28, size28
capacity:42, size29
capacity:42, size30
capacity:42, size31
capacity:42, size32
capacity:42, size33
capacity:42, size34
capacity:42, size35
capacity:42, size36
capacity:42, size37
capacity:42, size38
capacity:42, size39
capacity:42, size40
capacity:42, size41
capacity:42, size42
capacity:63, size43
capacity:63, size44
capacity:63, size45
capacity:63, size46
capacity:63, size47
capacity:63, size48
capacity:63, size49
capacity:63, size50
capacity:63, size51
capacity:63, size52
capacity:63, size53
capacity:63, size54
capacity:63, size55
capacity:63, size56
capacity:63, size57
capacity:63, size58
capacity:63, size59
capacity:63, size60
capacity:63, size61
capacity:63, size62
capacity:63, size63
capacity:94, size64
capacity:94, size65
capacity:94, size66
capacity:94, size67
capacity:94, size68
capacity:94, size69
capacity:94, size70
capacity:94, size71
capacity:94, size72
capacity:94, size73
capacity:94, size74
capacity:94, size75
capacity:94, size76
capacity:94, size77
capacity:94, size78
capacity:94, size79
capacity:94, size80
capacity:94, size81
capacity:94, size82
capacity:94, size83
capacity:94, size84
capacity:94, size85
capacity:94, size86
capacity:94, size87
capacity:94, size88
capacity:94, size89
capacity:94, size90
capacity:94, size91
capacity:94, size92
capacity:94, size93
capacity:94, size94
capacity:141, size95
capacity:141, size96
capacity:141, size97
capacity:141, size98
~~~
选几个数据分析一下:
0-1-2-3-4-6-9-13-19-28-42-63-94-141
从第二项开始:
2/2+2=3
3/2+3=4
4/2+4=6
6/2+6=9
9/2+9=13
13/2+13=19
19/2+19=28
28/2+28=42
42/2+42=63
63/2+63=94
94/2+94=141
**每次扩容50%**
删除容器中数据的时候,缓冲区大小并不会改变,仅仅只是清楚了其中的数据,只有在析构函数调用的时候vector才会自动释放缓冲区。
使用vector构造二维数组
最后更新于:2022-04-01 06:44:03
##实战c++中的vector系列--使用vector构造二维数组
二维数组有时候被用到,但是很少有人会使用vector来构造一个二维数组。
首先,需要明确的是,在计算机的世界中,根本不存在二维数组,只是使用者的一个概念罢了。其实我们所谓的二维数组也必须是一段连续的内存。
很多情况下,我们可以把常规的二维数组用一个vector表示,只要索引对应即可。
那么,我若一意孤行呢,我就想vector里面放一个vector呢?
~~~
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector <vector<int>> array(3);
for (int i = 0; i <3; i++)
array[i].resize(3);
for (int i = 0; i <3; i++)
for (int j = 0; j <3; j++)
array[i][j] = (i*j);
for (int i = 0; i <3; i++)
{
for (int j = 0; j <3; j++)
cout <<array[i][j] << " ";
cout <<endl;
}
array.resize(5);
array[3].resize(3);
array[4].resize(3);
//现在是5X3的数组了
cout << endl << endl;
for (int i = 0; i <5; i++)
for (int j = 0; j <3; j++)
array[i][j] = (i*j);
for (int i = 0; i <5; i++)
{
for (int j = 0; j <3; j++)
cout <<array[i][j] << " ";
cout <<endl;
}
}
//输出:
0 0 0
0 1 2
0 2 4
0 0 0
0 1 2
0 2 4
0 3 6
0 4 8
~~~
就是再使用“列”的时候,需要使用vector的resize方法,否则不能使用[]进行访问的。
这里也不能用vector的reserve分配容量,原因上一篇博客已经分析过了。
其实我想说的就是,如果想要构建所谓的二维数组,最重要的就是要使用resize分配容量。
copy set to vector(别混淆了reserve和resize)
最后更新于:2022-04-01 06:44:01
##实战c++中的vector系列--copy set to vector(别混淆了reserve和resize)
stl算法中有个copy函数,我们可以轻松的写出这样的代码:
~~~
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
double darray[10]={1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9};
vector<double> vdouble(10);
vector<double>::iterator outputIterator=vdouble.begin();
copy(darray,darray+10,outputIterator);
while(outputIterator!=vdouble.end())
{
cout<<*outputIterator<<endl;
outputIterator++;
}
getchar();
return 0;
}
~~~
于是你想使用copy来set to vector,于是你这样写道:
~~~
#include<iostream>
#include<vector>
#include<set>
int main()
{
std::set <double> input;
input.insert(5);
input.insert(6);
std::vector <double> output;
std::copy(input.begin(), input.end(), output.begin());
return 0;
}
~~~
编译通过,运行的时候出现错误。
why?
方法一
如果你在定义output的时候,指定其大小,错误就会消失:
~~~
#include<iostream>
#include<vector>
#include<set>
int main()
{
std::set <double> input;
input.insert(5);
input.insert(6);
std::vector <double> output(2);//指明大小
std::copy(input.begin(), input.end(), output.begin());
std::cout << output.size() << std::endl;
return 0;
}
~~~
方法二:使用**back_inserter**
back_inserter 是iterator适配器,它使得元素被插入到作为实参的某种容器的尾部
~~~
#include<iostream>
#include<vector>
#include<set>
#include<iterator>
int main()
{
std::set <double> input;
input.insert(5);
input.insert(6);
std::vector <double> output;
std::copy(input.begin(), input.end(), std::back_inserter(output));
std::cout << output.size() << std::endl;
return 0;
}
~~~
再继续vetor to vector:
~~~
#include<iostream>
#include<vector>
#include<set>
#include<iterator>
int main()
{
std::vector<std::string> v, orig;
orig.push_back("first");
orig.push_back("second");
v = orig;
v.insert(v.end(), v.begin(), v.end());
// Now v contains: { "first", "second", "", "" }
v = orig;
std::copy(v.begin(), v.end(), std::back_inserter(v));
v = orig;
v.reserve(v.size() * 2);
v.insert(v.end(), v.begin(), v.end());
// Now v contains: { "first", "second", "first", "second" }
v = orig;
v.reserve(v.size() * 2);
std::copy(v.begin(), v.end(), std::back_inserter(v));
// Now v contains: { "first", "second", "first", "second" }
// GOOD (best):
v = orig;
v.insert(v.end(), orig.begin(), orig.end()); // note: we use different vectors here
// Now v contains: { "first", "second", "first", "second" }
return 0;
}
~~~
再看这个:如果不resize,就会崩溃,把resize换成reserve也会崩溃,和解?
~~~
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
int myints[] = { 10, 20, 30, 40, 50, 60, 70 };
vector<int> myvector;
vector<int>::iterator it;
//myvector.resize(7); // 为容器myvector分配空间 ,不resize会崩溃
copy(myints, myints + 7, myvector.begin());
cout << "myvector contains: ";
for (it = myvector.begin(); it != myvector.end(); ++it)
{
cout << " " << *it;
}
cout << endl;
return 0;
}
~~~
================================================================
vector有reserve何resize,二者何为不同?
vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector的capacity同时也增加了它的size!
原因如下:
reserve是容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容器内的元素。加入新的元素时,要调用push_back()/insert()函数。
~~~
resize是改变容器的大小,且在创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。此时再调用push_back()函数,是加在这个新的空间后面的。
两个函数的参数形式也有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小, 第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。
~~~
看看实例:
~~~
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int> vector_for_reserve;
vector<int> vector_for_resize;
vector_for_reserve.reserve(4);
vector_for_resize.resize(4);
//size:0 capacity:4
cout << vector_for_reserve.size() << " " << vector_for_reserve.capacity() << endl;
//size :4 capacity:4
cout << vector_for_resize.size() << " " << vector_for_resize.capacity() << endl;
vector_for_reserve[0] = 1;//错误
vector_for_resize[0] = 1;
return 0;
}
~~~
将迭代器转换为索引
最后更新于:2022-04-01 06:43:59
##实战c++中的vector系列--将迭代器转换为索引
stl的迭代器很方便 用于各种算法。
但是一想到vector,我们总是把他当做数组,总喜欢使用下标索引,而不是迭代器。
这里有个问题就是如何把迭代器转换为索引:
~~~
#include <vector>
typedef std::vector<char *> MYARRAY;
// This does the trick
inline const int iterator_to_index(MYARRAY &a, MYARRAY::iterator it)
{
return it - a.begin();
}
// Example use
main()
{
MYARRAY a;
int index;
a.push_back("one");
a.push_back("two");
a.push_back("three");
for (MYARRAY::iterator it = a.begin(); it != a.end(); it++)
{
index = iterator_to_index(a, it);
printf("index=%d\n", index);
}
}
~~~
一、数组习惯用法
对于内置数组我们可以显式地把数组的元素初始化为一组常量值,例如 :
int ia[ 6 ] = { -2, -1, 0, 1, 2, 1024 };
我们不能用同样的方法显式地初始化 vector ,但是可以将 vector 初始化为一个已有数组的全部或一部分,只需指定希望被用来初始化 vector 的数组的开始地址以及数组最末元的下一位置来实现,例如:
// 把 ia 的 6 个元素拷贝到 ivec 中
vector ivec( ia, ia+6 );
被传递给ivec 的两个指针标记了用来初始化对象的值的范围, 第二个指针总是指向要拷贝的末元素的下一位置 ,标记出来的元素范围也可以是数组的一个子集,例如 :
// 拷贝 3 个元素 ia[2], ia[3], ia[4]
vector ivec( &ia[ 2 ], &ia[ 5 ] );
与内置数组不同 vector 可以被另一个 vector 初始化 或被赋给另一个 vector
注意 下面的定义
~~~
vector< int > ivec;
ivec[ 0 ] = 1024; //错误
~~~
就是错误的 ,因为 ivec 还没有第一个元素 ,我们只能索引 vector 中已经存在的元素 size()操作返回 vector 包含的元素的个数 。
下面的错误并不少见:
~~~
const int size = 7;
int ia[ size ] = { 0, 1, 1, 2, 3, 5, 8 };
vector< int > ivec( size );
for ( int ix = 0; ix < size; ++ix )
ivec.push_back( ia[ ix ]);
~~~
程序结束时ivec 包含 14 个元素, ia 的元素从第八个元素开始插入。
构造、operator=和assign区别
最后更新于:2022-04-01 06:43:56
##实战c++中的vector系列--构造、operator=和assign区别
vector也许是实际过程中使用最多的stl容器,看似简单,其实有很多技巧和陷阱。
着重看一看vector的构造,暂时按照C++11:
~~~
default (1)
explicit vector (const allocator_type& alloc = allocator_type());
fill (2)
explicit vector (size_type n);
vector (size_type n, const value_type& val,
const allocator_type& alloc = allocator_type());
range (3)
template <class InputIterator>
vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
copy (4)
vector (const vector& x);
vector (const vector& x, const allocator_type& alloc);
move (5)
vector (vector&& x);
vector (vector&& x, const allocator_type& alloc);
initializer list (6)
vector (initializer_list<value_type> il,
const allocator_type& alloc = allocator_type());
~~~
直接看看下面的代码,就知道如何构造一个vector了:
~~~
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> first; // default (1)
std::vector<int> second (4,100); // fill (2)
std::vector<int> third (second.begin(),second.end()); // range (3)
std::vector<int> fourth (third); // a copy of third
// the iterator constructor can also be used to construct from arrays:
int myints[] = {16,2,77,29};
std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );
std::cout << "The contents of fifth are:";
for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
~~~
===========================================================
vector重载了=运算符,也有一个叫assign的方法,而且有什么区别吗?
**std::vector::operator=**
直接代码:
~~~
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> foo (3,0);
std::vector<int> bar (5,0);
bar = foo;
foo = std::vector<int>();
std::cout << "Size of foo: " << int(foo.size()) << '\n';
std::cout << "Size of bar: " << int(bar.size()) << '\n';
return 0;
}
//结果:
Size of foo: 0
Size of bar: 3
~~~
这里需要说明的是:
replacing its current contents
modifying its size accordingly
**std::vector::assign**
同样直接代码:
~~~
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> first;
std::vector<int> second;
std::vector<int> third;
first.assign (7,100); // 7 ints with a value of 100
std::vector<int>::iterator it;
it=first.begin()+1;
second.assign (it,first.end()-1); // the 5 central values of first
int myints[] = {1776,7,4};
third.assign (myints,myints+3); // assigning from array.
std::cout << "Size of first: " << int (first.size()) << '\n';
std::cout << "Size of second: " << int (second.size()) << '\n';
std::cout << "Size of third: " << int (third.size()) << '\n';
return 0;
}
//输出:
Size of first: 7
Size of second: 5
Size of third: 3
~~~
这里同样需要说明:
replacing its current contents
modifying its size accordingly
前言
最后更新于:2022-04-01 06:43:54
> 原文出处:[实战c++中的vector系列专栏文章](http://blog.csdn.net/column/details/wangshubovector.html)
> 作者:[王书博](http://blog.csdn.net/wangshubo1989)
**本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!**
# 实战c++中的vector系列
> 本专栏主要记录和讲诉实际工作中,关于vector的一些操作,一些tips和一些tricks.