Notes from C++ Primer

Initialize container by iterator

When copy a container to another, the container type and element type must be match at the same time:

vector<int> ivec;
vector<int> ivec2(ivec); // ok: ivec is vector<int>
list<int> ilist(ivec); // error: ivec is not ilist<int>
vector<double> dvec(ivec); // error: ivec holds int not double

Use iterator to intialize container:

// initialize slist with copy of each element of svec
list<string> slist(svec.begin(), svec.end()); // find midpoint in the vector
vector<string>::iterator mid = svec.begin() + svec.size() / 2; // initialize front with first half of svec: the elements up to but not including *mid
deque<string> front(svec.begin(), mid); // initialize front with second half of svec: the elements *mid through end of svec
deque<string> back(mid, svec.end());

Because the pointer is iterator, so we can use pointer to initialize container.

char *words[] = {"stately", "plump", "buck", "mulligan"};

// calculate how many elements in words
size_t words_size = sizeof[words] / sizeof(char *); // use entire array to initialize words2
list<string> words2(words, words + words_size);

Initialize container by specifying size

We can use variable to specify the size of container. And it's alternative to assign the initial element or not.

const list<int>::size_type list_size = 64;
list<string> slist(list_size, "eh?"); // 64 strings, each is eh? ... list<int> ilist(list_size); // 64 elements, each initialized to 0 // svec has as many elements as the return value from tet_word_count
extern unsigned get_word_count(const string &file_name);
vector<string> svec(get_word_count("Chimera"));

P.S.: Only the sequential container can be initialized by size.

The type of container must satisfy two base conditions:

  • the element supports assignment
  • element can be copied

Some operations of container only can be used when the container element supports corresponding operation. For example, if type Foo doesn't have default constructor, its constructor has one int formal parameter. Then vector<Food> can't be initialized only by assigning size:

vector<Foo> empty;        // ok: no need for element default constructor
vector<Foo> bad(10); // error: no default constructor for Foo
vector<Foo> ok(10, 1); // ok: each element initialized to 1

As container satisfy the above two base conditions, then container can be container type. But when we define the contianer of container type, we need to notice the space between close ">":

// note spacing: use "> >" not ">>" when specifying a container element type
vector< vector<string> > lines; // vector of vectors
vector< vector<string> > lines; // ok: space required between close ">"
vecotr< vector<string>> lines; // error: >> treated as shift operator

When we use iterator, only vector and deque supports using position of element accessing container element:

vector<int>::iterator iter = vec.begin() + vec.size() / 2;

...

// copy elements from vec into ilist
list<int> ilist(vec.begin(), vec.end());
ilist.begin() + ilist.size() / 2; // error: no addition on list iterators.

Adding elements in sequential container

Add elements at the end:

list<int> ilist;
// add elements at the end of ilist
for(size_t ix = 0; ix != 4; ++ix)
ilist.push_back(ix);

Add elements at the beginning, which only can be used by list and deque:

// add elements to the start of ilist
for(size_t ix = 0; ix != 4; ++ix)
ilist.push_front(ix);

When we add elements to the container, system only copy the value into the container. The object copied and element in container are separate and independent.

Add element at specifying position:

  1. c.insert(p, t): inserting element with value $t$ in front of iterator p, return the iterator of new element in container.

    vector<string> svec;
    list<string> slist;
    string spouse("Beth"); // equivalent to calling slist.push_front(pouse);
    slist.insert(slist.begin(), spouse); // no push_front on vector but we can insert before begin()
    // warning: inserting anywhere but at the end of a vector is an expensive operation
    svec.insert(svec.begin(), spouse); ... slist.insert(iter, spouse); // insert spouse just before iter ... list<string> lst;
    list<string>::iterator iter = lst.begin();
    while(cin >> word)
    iter = lst.insert(iter, word); // same as calling push_front
  2. c.insert(p, n, t): insert $n$ elements with same value $t$ in front of iterator p, return void:
    svec.insert(svec.end(), 10, "Anna");
    
  3. c.insert(p, b, e): insert elements from iterator b to just before iterator e in front of p, return void:
    string sarray[4] = {"quasi", "simba", "frollo", "scar"};
    
    // insert all the elements in sarray and at the end of slist
    slist.insert(slist.end(), sarray, sarray + 4); list<string>::iterator slist_iter = slist.begin();
    // insert last two elements of sarray before slist_iter
    slist.insert(slist_iter, sarray + 2, sarray + 4);

The insert and push operation both may make the iterator invalid especially in a loop. It's better to ensure the update of iterators after every steps of a loop.

vector<int>::iterator first = v.begin(), last = v.end();	// cache end iterator

// disaster: behavior of this loop is undefined
while(first != last)
{
// do some processing // insert new value and reassign first, which otherwise would be invalid
first = v.insert(first, 42);
++first; // advance first just pass the element we added
}

So, in order to avoid cache end iterator, we need to keep updating:

// safer: recalculate end on each trip whenever the loop adds/erases elements
while(first != v.end())
{
// do some processing
first = v.insert(first, 42); // insert new value
++first; // advance first just pass the element we added
++first; // advance the element we just operated
}

Container size operation

There're two ways to resize container. If the current size of container is larger than the new container, the tailing elements will be deleted.

  • c.resize(n): make size of the container to be $n$.
  • c.resize(n, t): make size of the container to be $n$, and all adding new elements will be $t$.
list<int> ilist(10, 42);	// 10 ints: each has value 42
ilist.resize(15); // adds 5 elements of value 0 to back of ilist
ilist.resize(25, -1); // adds 10 elements of value -1 to back of ilist
ilist.resize(5); // erases 20 elements from the back of ilist

Access element

If the container is not empty, then we can use front() and back() to access first and last elements:

// check that there are elements before dereferencing an iterator
// or calling front or back
if(!ilist.empty())
{
// val and val2 refer to the same element
list<int>::reference val = *ilist.begin();
list<int>::reference val2 = ilist.front(); // last and last2 refer to the same element
list<int>::reference last = *--ilist.end();
list<int>::reference last2 = ilist.back();
}

Before calling front() and back(),we must check if the container is empty. The of dereferencing empty container's iterator and calling front() and back() are undefined.

In order to be safer, we can call at() to access element of container:

vector<string> svec;	// empty vector
cout << svec[0]; // run-time error: There are no elements in svec!
cout << svec.at(0); // throw out_of_range exception

Delete elements

We can use pop_font() and pop_back() to erase the first and last elements. But pop_front() only can be used by list and deque containers. They all return void. So if we want to get the deleted element, we need to call front() or back() before calling pop_font() and pop_back().

while(ilist.empty())
{
process(ilist.front()); // do something with the current top of ilist
ilist.pop_front(); // done: remove first element
}

The way to delete a piece of elements is using an iterator or a couple of iterators. They both return an iterator indicating the element just after the deleted element or elements. Before using erase, we must check if the element we want to delete is existing.

#include<algorithm>
...
string searchValue("Quasimodo");
list<string>::iterator iter = find(slist.begin(), slist.end(), searchValue);
if(iter != slist.end())
slist.erase(iter);

If we want to erase all the elements in the container, we can call clear() function or pass begin and end iterator to erase function.

slist.clear();				        // delete all the elements within the container
slist.erase(slist.begin(), slist.end()); // equivalent

More over, erase function supports delete a piece of elements as mentioned above:

// delete range of elements between two values
list<string>::iterator elem1, elem2; // elem1 refers to val1
elem1 = find(slist.begin(), slist.end(), val1);
// elem2 refers to val2
elem2 = find(slist.begin(), slist.end(), val2); // erase range from val1 to val2 but not including val2
slist.erase(elem1, elem2);

Assignment and swap

Assignment operator(=) of container is equivalent to erase all the elements of left operand and then insert all the elements of right operand into left operand:

c1 = c2;	// replace contents of c1 with a copy of elements in c2

// equivalent operation using erase and insert
c1.erase(c1.begin(), c1.end()); // delete all the elements in c1
c1.insert(c2.begin(), c2.end()); // insert c2

Assign operation( assign() ) is also equivalent to delete all the elements in the container and then inserts new elements as specified by the assignments. But they do have DIFFERENCE:

Assignment operator(=) is the same as copy constructor only can be used when the two operands have same container and elements type. So, if we want to assign elements of a different but compatible element type and/or from a different container type, then we MUST use the assign operation: assign().

The code is almost the same as assignment operator:

// equivalent to slist1 = slist2
slist1.assign(slist2.begin(), slist.end()); ... // equivalent to: slist1.clear()
// follow by slist1.insert(slist1.begin(), 10, "Hiya!");
slist1.assign(10, "Hiya!"); // 10 elements: each one is Hiya!

Operation swap executes much faster than assign operation. More important it can guarantee the iterators validate, because no elements are removed.

vector<string> svec1(10);	// vector with 10 elements
vector<string> svec2(24); // vector with 24 elements
svec1.swap(svec2);

Capacity and reserve member variable

vector class offers two member capacity and reserve to implement partial memory allocation. size is the number of current elements in the container. But the capacity indicates the total number of elements can be stored in container before reallocating more memory space:

vector<int> ivec;

// size should be zero; capacity is implementation defined
cout << "ivec: size: " << ivec.size()
<< " capacity: " << ivec.capacity() << endl; // give ivec 25 elements
for(vector<int>::size_type ix = 0; ix != 24; ++ix)
ivec.push_back(ix); // size should be 24; capacity will be >= 24 and is implementation defined
cout << "ivec: size: " << ivec.size()
<< " capacity: " << ivec.capacity() << endl;

After the execution, we get the answer:

ivec: size:  capacity:
ivec: size: capacity:

Now, we can use reserve() funtion to change the size of capacity:

ivec.reserve(50);	// sets capacity to at least 50; might be more

// size should be 24; capacity will be >= 50 and is implementation defined
cout << "ivec: size: " << ivec.size()
<< " capacity: " << ivec.capacity() << endl;

then the result will be:

ivec: size:  capacity: 

Now, let's use an example to show the situation when we use up the reserved capacity:

// add elements to use up the excess capacity
while(ivec.size() != ivec.capacity())
ivec.push_back(0); // size should be 50; capacity should be unchanged
cout << "ivec: size: " << ivec.size()
<< " capacity: " << ivec.capacity() << endl;

the result is:

ivec: size:  capacity: 

If we continue to add element, then the vector has to reallocate its memory:

ivec.push_back(42);		// add one more element

// size should be 51; capacity will be >= 51 and is implementation defined
cout << "ivec: size: " << ivec.size()
<< " capacity: " << ivec.capacity() << endl;

the result becomes:

ivec: size:  capacity: 

Sequential Container的更多相关文章

  1. C++Primer 5th Chap9 Sequential Container

    vector 可变大小数组,支持快速随机访问(在除了尾部之外部分插入删除元素很慢) deque 双端队列,支持快速随机访问(在头尾插入删除元素很快) list 双向链表,仅支持双向顺序访问(在任何位置 ...

  2. pytorch--nn.Sequential学习

    nn.SequentialA sequential container. Modules will be added to it in the order they are passed in the ...

  3. Container Adaptors

    Notes from C++ Primer stack and queue: based on deque priority_queue:    based on vector Standard li ...

  4. torch.nn.Sequential()详解

    参考:官方文档    源码 官方文档 nn.Sequential A sequential container. Modules will be added to it in the order th ...

  5. Pytorch——torch.nn.Sequential()详解

    参考:官方文档    源码 官方文档 nn.Sequential A sequential container. Modules will be added to it in the order th ...

  6. Java基础常见英语词汇

    Java基础常见英语词汇(共70个) ['ɔbdʒekt] ['ɔ:rientid]导向的                             ['prəʊɡræmɪŋ]编程 OO: object ...

  7. IT软件开发常用英语词汇

    Aabstract 抽象的abstract base class (ABC)抽象基类abstract class 抽象类abstraction 抽象.抽象物.抽象性access 存取.访问access ...

  8. computer English

    算法常用术语中英对照Data Structures 基本数据结构Dictionaries 字典PriorityQueues 堆Graph Data Structures 图Set Data Struc ...

  9. STL六大组件之——容器知识大扫盲

    STL中的容器主要涉及顺序容器类型:vector.list.deque,顺序容器适配器类型:stack.queue.priority_queue.标准库中的容器分为顺序容器和关联容器.顺序容器(seq ...

随机推荐

  1. python3 发送邮件

    import smtplibfrom email.mime.text import MIMETextdef SendEmail(fromAdd,toAdd,subject,text): _pwd = ...

  2. 多线程利器-队列(queue)

    #队列有3中模式,先进先出,先进后出,优先级 1:先进先出import queue q = queue.Queue() #默认是先进先出q.put(12)q.put('jack')q.put({'na ...

  3. tmp32dll\sha1-586.asm(1432) : error A2070:invalid instruction operands 编译openssl出错

    vs命令行工具编译openssl最新版本的时候报perl版本太低. 后来换了openssl 1.0.2的版本旧版本到是可以正常编译了,但是1.0.2应该是版本还是优点新. 编译的时候报了下面的错误: ...

  4. cacti监控服务器

    1.Cacti基本概念详解 Cacti是用php语言实现的一个软件,它的主要功能是用snmp服务获取数据,然后用rrdtool储存和更新数据,当用户需要查看数据的时候用rrdtool生成图表呈现给用户 ...

  5. 关于Shader的学习记录

    float4 _EmissiveColor; float4 _AmbientColor; float _MySliderValue; void surf (Input IN, inout Surfac ...

  6. keil mdk5安装

  7. 【Django】网页跳转的问题

    这两天有个比较奇怪了问题困扰着我,就是网页跳转之后页面没有变化,虽然url已经变了,但是页面还是原来的,只是表单数据清空了 就是http://127.0.0.1:8000/signup_signin/ ...

  8. 20162322 朱娅霖 作业011 Hash

    20162322 2017-2018-1 <程序设计与数据结构>第十一周学习总结 教材学习内容总结 哈希方法 一.定义 哈希:次序--更具体来说是项在集合中的位置--由所保存元素值的某个函 ...

  9. 针对piix4_smbus ****host smbus controller not enabled的解决方法

    SMBus 目录 SMBus与I2C的差别 SMBus 是 System Management Bus 的缩写,是1995年由Intel提出的,应用于移动PC和桌面PC系统中的低速率通讯.它主要是希望 ...

  10. 复用微信小程序源码包后仍然有原小程序的版本管理怎么处理

    前言: 复用微信小程序源码包后,重新创建项目导入源码包,会发现开发者工具版本管理中仍然有原来小程序的版本,这样就不太好了.毕竟是一个新的小程序,需要有新的版本控制的.那么这个问题怎么处理呢? 解决方案 ...