Deleting the element 4th element in a vector requires the following code:
vector<int> v;
....
....
v.erase(v.begin()+3); // Erase v[3], i.e. the 4th element
I'm wondering why we need the v.begin() part.
It would be nicer just to write:
v.erase(3); // Erase v[3], i.e. the 4th element
The begin() is a member of vector so the erase method could just as well handle that part for us so that our code would be more readable and easy to understand.
There is probably a good reason and I like to know.
Can someone explain or link an explanation?
Thanks.
If this is something you'd like to be able to do, it's easy enough to come up with a function template (or is it a template function?) that will do this with a slightly different, but probably similar enough syntax:
#include <iostream>
#include <ostream>
#include <vector>
template <typename T>
void erase_at( T& container, size_t pos)
{
container.erase(container.begin() + pos);
}
using namespace std;
int main() {
vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
for (vector<int>::iterator i = v.begin(); i != v.end(); ++i) {
cout << *i << " ";
}
cout << endl;
erase_at(v, 3); // <-- instead of `v.erase(v.begin() + 3)`
for (vector<int>::iterator i = v.begin(); i != v.end(); ++i) {
cout << *i << " ";
}
cout << endl;
return 0;
}
Presumably, one of the key things here is to create a uniform interface to the standard library containers.
Let's look at std::set<T>, std::vector<T>, and std::list<T>. In only one of these cases do we have access to a random access iterator. In all the other cases, getting container.begin() + 3 can be relatively expensive. Especially when the user probably has an iterator already, because they found the element exists in the object and they want to remove it.
Because of vector.erase receives iterator, but not integer.
You can see that on documentation http://www.cplusplus.com/reference/vector/vector/erase/
STL developers, I think, wanted to make unique interface of erasing on all container generic classes(vector, list, etc)
Related
I have two code sample, which do exactly same thing. One is in C++03 and C++11.
C++ 11
int main()
{
vector<int> v = {1,2,3};
int count = 0;
for each (auto it in v)
{
cout << it<<endl;
if (count == 0)
{
count++;
v.push_back(4);//adding value to vector
}
}
return 0;
}
C++ 03
int main()
{
vector<int> v = {1,2,3};
int count = 0;
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it<<endl;
if (count == 0)
{
count++;
v.push_back(4);//adding value to vector
}
}
return 0;
}
Both the codes are giving following exception.
Now when I see vector::end() implementation,
iterator end() _NOEXCEPT
{
// return iterator for end of mutable sequence
return (iterator(this->_Mylast, this));
}
Here, inline function clearly takes _Mylast to calculate end. So, when I add, it pointer will be incremented to next location, like _Mylast++. Why I am getting this exception?
Thanks.
A vector stores its elements in contiguous memory. If that memory block needs to be reallocated, iterators become invalid.
If you need to modify the vector's size while iterating, iterate by index instead of iterator.
Another option is to use a different container with a different iterator behavior, for example a list will allow you to continue iterating as you insert items.
And finally, (dare I suggest this?) if you know the maximum size your vector will grow to, .reserve() it before iterating over it. This will ensure it doesn't get reallocated during your loop. I am not sure if this behavior is guaranteed by the standard though (maybe someone can chime in); I would definitely not do it, considering iterating by index is perfectly safe.
Your push_back is invalidating the iterator you're using in the for loop, because the vector is reallocating its memory, which invalidates all iterators to elements of the vector.
The idiomatic solution for this is to use an insert_iterator, like the one you get from calling std::back_insterter on the vector. Then you can do:
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
std::vector<int> v;
auto inserter = std::back_inserter(v);
for(int i=0; i<100; ++i)
inserter = i;
for(const auto item : v)
std::cout << item << '\n';
}
And it will ensure its own validity even through reallocation calls of the underlying container.
Live demo here.
I have a list:
list<Student>* l;
and I would like to get an element at a specified index. Example:
l->get(4)//getting 4th element
Is there a function or method in list which enables it to do so?
std::list does not have a random access iterator, so you have to step 4 times from the front iterator. You can do this manually or with std::advance, or std::next in C++11, but bear in mind that both O(N) operations for a list.
#include <iterator>
#include <list>
....
std::list<Student> l; // look, no pointers!
auto l_front = l.begin();
std::advance(l_front, 4);
std::cout << *l_front << '\n';
Edit: The original question asked about vector too. This is now irrelevant, but may be informative nonetheless:
std::vector does have random access iterators, so you can perform the equivalent operation in O(1) via the std::advance, std::next if you have C++11 support, the [] operator, or the at() member function:
std::vector<Student> v = ...;
std::cout << v[4] << '\n'; // UB if v has less than 4 elements
std::cout << v.at(4) << '\n'; // throws if v has less than 4 elements
Here's a get() function that returns the _ith Student in _list.
Student get(list<Student> _list, int _i){
list<Student>::iterator it = _list.begin();
for(int i=0; i<_i; i++){
++it;
}
return *it;
}
If you want random access to elements, you should use a vector and then you can use [] operator to get the 4th element.
vector<Student> myvector (5); // initializes the vector with 5 elements`
myvector[3]; // gets the 4th element in the vector
For std::vector you can use
myVector.at(i) //retrieve ith element
I have a std::map with both key and value as integers. Now I want to randomly shuffle the map, so keys point to a different value at random. I tried random_shuffle but it doesn't compile. Note that I am not trying to shuffle the keys, which makes no sense for a map. I'm trying to randomise the values.
I could push the values into a vector, shuffle that and then copy back. Is there a better way?
You can push all the keys in a vector, shuffle the vector and use it to swap the values in the map.
Here is an example:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <random>
#include <ctime>
using namespace std;
int myrandom (int i) { return std::rand()%i;}
int main ()
{
srand(time(0));
map<int,string> m;
vector<int> v;
for(int i=0; i<10; i++)
m.insert(pair<int,string>(i,("v"+to_string(i))));
for(auto i: m)
{
cout << i.first << ":" << i.second << endl;
v.push_back(i.first);
}
random_shuffle(v.begin(), v.end(),myrandom);
vector<int>::iterator it=v.begin();
cout << endl;
for(auto& i:m)
{
string ts=i.second;
i.second=m[*it];
m[*it]=ts;
it++;
}
for(auto i: m)
{
cout << i.first << ":" << i.second << endl;
}
return 0;
}
The complexity of your proposal is O(N), (both the copies and the shuffle have linear complexity) which seems optimal (looking at less elements would introduce non-randomness into your shuffle).
If you want to repeatedly shuffle your data, you could maintain a map of type <Key, size_t> (i.e. the proverbial level of indirection) that indexes into a std::vector<Value> and then just shuffle that vector repeatedly. That saves you all the copying in exchange for O(N) space overhead. If the Value type itself is expensive, you have an extra vector<size_t> of indices into the real data on which you do the shuffling.
For convenience sake, you could encapsulate the map and vector inside one class that exposes a shuffle() member function. Such a wrapper would also need to expose the basic lookup / insertion / erase functionality of the underyling map.
EDIT: As pointed out by #tmyklebu in the comments, maintaining (raw or smart) pointers to secondary data can be subject to iterator invalidation (e.g. when inserting new elements at the end that causes the vector's capacity to be resized). Using indices instead of pointers solves the "insertion at the end" problem. But when writing the wrapper class you need to make sure that insertions of new key-value pairs never cause "insertions in the middle" for your secondary data because that would also invalidate the indices. A more robust library solution would be to use Boost.MultiIndex, which is specifically designed to allow multiple types of view over a data structure.
Well, with only using the map i think of that:
make a flag array for each cell of the map, randomly generate two integers s.t. 0<=i, j < size of map; swap them and mark these cells as swapped. iterate for all.
EDIT: the array is allocate by the size of the map, and is a local array.
I doubt it...
But... Why not write a quick class that has 2 vectors in. A sorted std::vector of keys and a std::random_shuffled std::vector of values? Lookup the key using std::lower_bound and use std::distance and std::advance to get the value. Easy!
Without thinking too deeply, this should have similar complexity to std::map and possibly better locality of reference.
Some untested and unfinished code to get you started.
template <class Key, class T>
class random_map
{
public:
T& at(Key const& key);
void shuffle();
private:
std::vector<Key> d_keys; // Hold the keys of the *map*; MUST be sorted.
std::vector<T> d_values;
}
template <class Key, class T>
T& random_map<Key, T>::at(Key const& key)
{
auto lb = std::lower_bound(d_keys.begin(), d_keys.end(), key);
if(key < *lb) {
throw std::out_of_range();
}
auto delta = std::difference(d_keys.begin(), lb);
auto it = std::advance(d_values.begin(), lb);
return *it;
}
template <class Key, class T>
void random_map<Key, T>::shuffle()
{
random_shuffle(d_keys.begin(), d_keys.end());
}
If you want to shuffle the map in place, you can implement your own version of random_shuffle for your map. The solution still requires placing the keys into a vector, which is done below using transform:
typedef std::map<int, std::string> map_type;
map_type m;
m[10] = "hello";
m[20] = "world";
m[30] = "!";
std::vector<map_type::key_type> v(m.size());
std::transform(m.begin(), m.end(), v.begin(),
[](const map_type::value_type &x){
return x.first;
});
srand48(time(0));
auto n = m.size();
for (auto i = n-1; i > 0; --i) {
map_type::size_type r = drand48() * (i+1);
std::swap(m[v[i]], m[v[r]]);
}
I used drand48()/srand48() for a uniform pseudo random number generator, but you can use whatever is best for you.
Alternatively, you can shuffle v, and then rebuild the map, such as:
std::random_shuffle(v.begin(), v.end());
map_type m2 = m;
int i = 0;
for (auto &x : m) {
x.second = m2[v[i++]];
}
But, I wanted to illustrate that implementing shuffle on the map in place isn't overly burdensome.
Here is my solution using std::reference_wrapper of C++11.
First, let's make a version of std::random_shuffle that shuffles references. It is a small modification of version 1 from here: using the get method to get to the referenced values.
template< class RandomIt >
void shuffleRefs( RandomIt first, RandomIt last ) {
typename std::iterator_traits<RandomIt>::difference_type i, n;
n = last - first;
for (i = n-1; i > 0; --i) {
using std::swap;
swap(first[i].get(), first[std::rand() % (i+1)].get());
}
}
Now it's easy:
template <class MapType>
void shuffleMap(MapType &map) {
std::vector<std::reference_wrapper<typename MapType::mapped_type>> v;
for (auto &el : map) v.push_back(std::ref(el.second));
shuffleRefs(v.begin(), v.end());
}
I am new to the C++ language. I have been starting to use vectors, and have noticed that in all of the code I see to iterate though a vector via indices, the first parameter of the for loop is always something based on the vector. In Java I might do something like this with an ArrayList:
for(int i=0; i < vector.size(); i++){
vector[i].doSomething();
}
Is there a reason I don't see this in C++? Is it bad practice?
The reason why you don't see such practice is quite subjective and cannot have a definite answer, because I have seen many of the code which uses your mentioned way rather than iterator style code.
Following can be reasons of people not considering vector.size() way of looping:
Being paranoid about calling size() every time in the loop
condition. However either it's a non-issue or it can be trivially
fixed
Preferring std::for_each() over the for loop itself
Later changing the container from std::vector to other one (e.g.
map, list) will also demand the change of the looping mechanism,
because not every container support size() style of looping
C++11 provides a good facility to move through the containers. That is called "range based for loop" (or "enhanced for loop" in Java).
With little code you can traverse through the full (mandatory!) std::vector:
vector<int> vi;
...
for(int i : vi)
cout << "i = " << i << endl;
The cleanest way of iterating through a vector is via iterators:
for (auto it = begin (vector); it != end (vector); ++it) {
it->doSomething ();
}
or (equivalent to the above)
for (auto & element : vector) {
element.doSomething ();
}
Prior to C++0x, you have to replace auto by the iterator type and use member functions instead of global functions begin and end.
This probably is what you have seen. Compared to the approach you mention, the advantage is that you do not heavily depend on the type of vector. If you change vector to a different "collection-type" class, your code will probably still work. You can, however, do something similar in Java as well. There is not much difference conceptually; C++, however, uses templates to implement this (as compared to generics in Java); hence the approach will work for all types for which begin and end functions are defined, even for non-class types such as static arrays. See here: How does the range-based for work for plain arrays?
Is there any reason I don't see this in C++? Is it bad practice?
No. It is not a bad practice, but the following approach renders your code certain flexibility.
Usually, pre-C++11 the code for iterating over container elements uses iterators, something like:
std::vector<int>::iterator it = vector.begin();
This is because it makes the code more flexible.
All standard library containers support and provide iterators. If at a later point of development you need to switch to another container, then this code does not need to be changed.
Note: Writing code which works with every possible standard library container is not as easy as it might seem to be.
The right way to do that is:
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
it->doSomething();
}
Where T is the type of the class inside the vector. For example if the class was CActivity, just write CActivity instead of T.
This type of method will work on every STL (Not only vectors, which is a bit better).
If you still want to use indexes, the way is:
for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
v[i].doSomething();
}
Using the auto operator really makes it easy to use as one does not have to worry about the data type and the size of the vector or any other data structure
Iterating vector using auto and for loop
vector<int> vec = {1,2,3,4,5}
for(auto itr : vec)
cout << itr << " ";
Output:
1 2 3 4 5
You can also use this method to iterate sets and list. Using auto automatically detects the data type used in the template and lets you use it.
So, even if we had a vector of string or char the same syntax will work just fine
A correct way of iterating over the vector and printing its values is as follows:
#include<vector>
// declare the vector of type int
vector<int> v;
// insert elements in the vector
for (unsigned int i = 0; i < 5; ++i){
v.push_back(i);
}
// print those elements
for (auto it = v.begin(); it != v.end(); ++it){
std::cout << *it << std::endl;
}
But at least in the present case it is nicer to use a range-based for loop:
for (auto x: v) std::cout << x << "\n";
(You may also add & after auto to make x a reference to the elements rather than a copy of them. It is then very similar to the above iterator-based approach, but easier to read and write.)
There's a couple of strong reasons to use iterators, some of which are mentioned here:
Switching containers later doesn't invalidate your code.
i.e., if you go from a std::vector to a std::list, or std::set, you can't use numerical indices to get at your contained value. Using an iterator is still valid.
Runtime catching of invalid iteration
If you modify your container in the middle of your loop, the next time you use your iterator it will throw an invalid iterator exception.
Here is a simpler way to iterate and print values in vector.
for(int x: A) // for integer x in vector A
cout<< x <<" ";
With STL, programmers use iterators for traversing through containers, since iterator is an abstract concept, implemented in all standard containers. For example, std::list has no operator [] at all.
I was surprised nobody mentioned that iterating through an array with an integer index makes it easy for you to write faulty code by subscripting an array with the wrong index. For example, if you have nested loops using i and j as indices, you might incorrectly subscript an array with j rather than i and thus introduce a fault into the program.
In contrast, the other forms listed here, namely the range based for loop, and iterators, are a lot less error prone. The language's semantics and the compiler's type checking mechanism will prevent you from accidentally accessing an array using the wrong index.
don't forget examples with const correctness - can the loop modify the elements. Many examples here do not, and should use cont iterators. Here we assume
class T {
public:
T (double d) : _d { d } {}
void doSomething () const { cout << _d << endl; return; }
void changeSomething () { ++_d; return; }
private:
double _d;
};
vector<T> v;
// ...
for (const auto iter = v.cbegin(); iter != v.cend(); ++iter) {
iter->doSomething();
}
Note also, that with the C++11 notation, the default is to copy the element. Use a reference to avoid this, and/or to allow for original elements to be modified:
vector<T> v;
// ...
for (auto t : v) {
t.changeSomething(); // changes local t, but not element of v
t.doSomething();
}
for (auto& t : v) { // reference avoids copying element
t.changeSomething(); // changes element of v
t.doSomething();
}
for (const auto& t : v) { // reference avoids copying element
t.doSomething(); // element can not be changed
}
//different declaration type
vector<int>v;
vector<int>v2(5,30); //size is 5 and fill up with 30
vector<int>v3={10,20,30};
//From C++11 and onwards
for(auto itr:v2)
cout<<"\n"<<itr;
//(pre c++11)
for(auto itr=v3.begin(); itr !=v3.end(); itr++)
cout<<"\n"<<*itr;
int main()
{
int n;
int input;
vector<int> p1;
vector<int> ::iterator it;
cout << "Enter the number of elements you want to insert" << endl;
cin >> n;
for (int i = 0;i < n;i++)
{
cin >> input;
p1.push_back(input);
}
for(it=p1.begin();it!=p1.end();it++)
{
cout << *it << endl;
}
//Iterating in vector through iterator it
return 0;
}
conventional form of iterator
If you use
std::vector<std::reference_wrapper<std::string>> names{ };
Do not forget, when you use auto in the for loop, to use also get, like this:
for (auto element in : names)
{
element.get()//do something
}
i'm trying to use algorithm lib & vector lib to first copy a set of numbers from an array into a vector then printing it using iteration, where is the problem of my code?
and one thing is that i chose 2 way to do this iteration first using vec.begin() ; vec.end() method & the other one is for (i = 0 ; i < vec.capacity() ; i++)
both facing errors.
what should i do?
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int intArray[] = {5,6,8,3,40,36,98,29,75};
vector<int> vecList(9);
//vector<int>::iterator it;
copy (intArray, intArray+9,vecList);
//for(it = vecList.begin() ; it != vecList.end() ; it++)
for (int it = 0 ; it < vecList.capacity() ; it++)
{
cout<<*it<<endl;
}
system("pause");
return 0;
}
There are several improvements possible.
You confuse iterators with indices. An iterator it is a glorified pointer into the vector, that you need to derefence by typing *it. An index i is an offset from the beginning of the vector and saying vecList[i] will give you that element.
The initialization of the vector is best done using initializer lists (C++11), rather than reading from an array.
You need to loop to vecList.size(). The capacity of the vector is the size of the allocated storage space for the elements of the vector container. Looping is best done with a ranged-for loop as shown by Kerrek SB, or a std::for_each + a lambda expression, or a regular for loop as you did. In that case however, it's best to get into the habit of doing it != vecList.end() (instead of using <) and doing ++it instead of it++.
Note that I also used auto to avoid writing the explicit iterator type. It's also a good habit to get into using auto wherever you can.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
// initialize vector with a list of elements
vector<int> vecList {5,6,8,3,40,36,98,29,75};
// loop from begin() to end() of vector, doing ++it instead of it++
for (auto it = vecList.begin(); it != vecList.end(); ++it)
{
cout<<*it<<endl;
}
// the pause command is better done by setting a breakpoint in a debugger
return 0;
}
Output on Ideone (this uses the g++ 4.5.1 compiler, it's best to upgrade to at least that version to take advantage of C++11 features).
The problem is that you're confusing indexes and iterators.
w/ index:
for (int i = 0 ; i < vecList.size() ; it++)
{
cout<<vecList[i]<<endl;
}
w/ iterators
for (std::vector<int>::const_iterator it = vecList.begin() ; i != vecList.end() ; it++)
{
cout<<*it<<endl;
}
A. you need to iterate on vecList.size() not vecList.capacity() which mean how much memory the vector is reserving for himself (not how much of it is in use).
B. you tried to use the integer index it as an iterator with the call to *it, you should check Luchian Grigore answer for the right way to do it.
This isn't an answer, but I wanted to show how modern C++ allows you to do away with lots of the brittle dependencies on details:
int intArray[] = {5,6,8,3,40,36,98,29,75};
std::vector<int> vecList(std::begin(intArray), std::end(intArray));
for (int i : vecList) { std::cout << i << std::endl; }
Using iterators and algorithms idiomatically, you can often remove any explicit mention of details such as lengths of arrays, thus making your code more robust.
Typo mistake use : copy (intArray, intArray+9,vecList.begin());
so,
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
int main()
{
int intArray[] = {5,6,8,3,40,36,98,29,75};
vector<int> vecList(9);
vector<int>:: iterator it;
copy (intArray, intArray+9,vecList.begin());
for (it=vecList.begin();it!=vecList.end(); it++)
{
cout<<*it<<endl;
}
system("pause");
return 0;
}