What's the best way to select individual elements from a C++ std::vector?
I'm used to C-style arrays and this is the first time I'm using vectors.
I'm looking for something like:
std::vector<std::string> myvector;
astring = myvector[1];
bstring = myvector[3];
cstring = myvector[10];
And so on.
There are several ways to access elements in a std::vector:
myVector[3] - access the 4th element (0-indexed).
myVector.at(3) - access the 4th element with bounds checking. Throws an exception if the index is not less than the number of elements.
iterating over all elements with the standard algorithms: std::find(std::begin(myVector), std::end(myVector), 10).
Personally I've never found a use for at(), since I keep track of the index that I'm using anyway. I rarely just take a number from somewhere and stick it into [].
But be aware that accessing an index not less than the number of elements using [] is Undefined Behaviour (if the vector has 4 elements, you access them with 0, 1, 2, and 3). You are expected to be sure it is safe yourself. So in your example, this would be illegal, since you don't put anything into the vector first.
You ask for the best way... The answer is: There is no general best way
The best way is not always the same. It really depends on what your code is doing.
The best way also depends on what you want to achieve, e.g. best performance, best code maintainability, best code readability and so on.
The best way is also based on a personal view.
So just to repeat the answer: There is no general best way
Other answers mentions a number of different posibilities. I'll add one more.
// To iterate over all elements in a vector you can do
for (auto& e : someVector)
{
// Do something with e, e.g. print it
cout << e;
}
There are three general ways to access elements of a vector.
The first one is similar to accessing elements of an array using the subscript operator [].
For example
std::vector<std::string> v = { "Hello", "World" };
std::cout << v[0] << ' ' << v[1] << std::endl;
The second one is to use iterators similar to using pointers. For example
std::vector<std::string> v = { "Hello", "World" };
auto it = v.begin();
std::cout << *it << ' ' << *( it + 1 ) << std::endl;
The third one is to use member function at that checks the boundaries of a vector and throws an exception when an attempt is made to access memory beyond the vector
std::vector<std::string> v = { "Hello", "World" };
std::cout << v.at( 0 ) << ' ' << v.at( 1 ) << std::endl;
Also there are methods to acess the first and the last elements of a vector
for example
std::vector<std::string> v = { "Hello", "World" };
std::cout << v.front() << ' ' << v.back() << std::endl;
To access sequentially all elements of a vector you can use three kinds of loops.
For example
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
or
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( std::vector<int>::size_type i = 0; i < v.size(); i++ ) std::cout << v[i] << ' ';
std::cout << std::endl;
or
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( auto it = v.begin(); it != v.end(); ++it ) std::cout << *it << ' ';
std::cout << std::endl;
Simple use operator[] as you do with arrays. If you want boundary checking use at().
That is generally how you access vectors, they were made to be similar to arrays using the indexing operator.
However, once you when you declare a vector like you do, without passing any arguments to the constructor the vector is empty, which means that any indexing will be out of bounds and you will have undefined behavior.
If you want to specify an initial size, you could pass an argument to the constructor:
std::vector<std::string> myvector(11); // Creates a vector of 11 elements
If you never will change the size of the vector, if the size is fixed at the time of compilation using a compile-time constant, then you should probably be suing std::array instead:
std::array<std::string, 11> myarray;
You can access (i.e. select some element) a std::vector similar to C-style arrays i.e. by using indexes. Similar to arrays, no bound checking is performed in case of std::vector as well when you access some element which is not present. For example, you have inserted 10 elements in vector v but accessing 200th element using v[200] - but it could result undefined behavior, so be careful.
Related
When I'm trying to print the values of an array, its memory location is getting printed instead of values. What am I doing wrong?
int main()
{
int list[3];
for (int i=0; i<3; i++)
{
list[i] = i;
std::cout<<list<<std::endl;
}
}
OUTPUT: 0x7ffffef79550
C++ doesn't provide an overload for arrays when using the iostream library. If you want to print the values of an array, you'll need to write a function or find one somebody else has written.
What's happening under the hood is list is decaying to an int*, and that's what you're seeing printed.
This looks like a typographical error:
std::cout << list
You want to print a specific element of the array, right?
std::cout << list[i]
When printing "the whole array" without index, the pointer to first element is printed (see the other answer for reason).
std::cout << list << std::endl;
You're printing the array object itself. What do you expect to see? The name of the array identifier? The address of the first element in the array? (actually this is what happens in your case). Or do you expect the array to neatly iterate over it's elements and build a comma separated string of all the values and output it to the stream? If this is what you want, you have to implement it yourself.
template <std::size_t N>
std::ostream& operator<<(std::ostream& out, int (&arr)[N]) {
std::copy(std::begin(arr), std::end(arr), std::ostream_iterator<int>{out, ", "});
return out;
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
std::cout << arr << std::endl; // Ok, prints "1, 2, 3, 4, 5, ".
}
You need to dereference the list. Instead of:
std::cout << list << std::endl;
do:
std::cout << *list << std::endl;
Is there a way to randomly select an element from an enumeration in a type-safe way?
The best way to do it, that I could find, is to introduce a terminator value as the last element of the enum, so you know how many values there are, then generate a random integer in the appropriate range that you cast to the enum. But a terminator value does not represent anything, so then you have an invalid enum value, and this is not type-safe. Is there a better way to do it in the latest C++ standards?
This seems like a good use case for a std::map
std::map<std::string, const int> nicer_enum {{"Do", 3}, {"Re", 6}, {"Mi", 9}};
std::cout << nicer_enum["Re"] << '\n'; // 6
auto elem = nicer_enum.cbegin();
std::srand(std::time(nullptr));
std::advance(elem, std::rand() % nicer_enum.size());
std::cout << elem->second << '\n'; // 3, 6 or 9
for (const auto &kv : nicer_enum)
std::cout << kv.first << ": " << kv.second << ' '; // Do: 3 Mi: 9 Re: 6
std::cout << '\n';
How to deep erase a vector?
Consider the following code.
#include<algorithm>
#include<iostream>
#include<iterator>
#include<vector>
using namespace std;
int main(){
vector<int> v {1,2,3,4,5};
for_each(begin(v),end(v),[&v](int& n){
static auto i = (int)0;
if(n == 2){
v.erase ( begin(v) +2, end(v));
}
cout << n << " having index " << i++ << endl;
});
v.erase ( begin(v) +2, end(v));
cout << v.size() << endl << v[4] << endl;
}
Output is
1 having index 0
2 having index 1
3 having index 2
4 having index 3
5 having index 4
2
4
What I want is accessing v[i] for any i from 2 to 4 to be invalid and compiler to throw an error.
In simpler words how to deep erase a vector?
You're triggering undefined behavior and therefore your results cannot be trusted.
If you need to check for boundaries use std::vector::at
vector<int> v{ 1,2,3,4,5 };
v.erase(begin(v) + 2, end(v));
try {
auto val = v.at(4);
} catch (std::out_of_range&) {
cout << "out of range";
}
Unless you code your own facility or workaround, you can't have such compile-time checks with std::vector. More information and some suggestions here: https://stackoverflow.com/a/32660677/1938163
I do not have time right now to give examples, but the only way I can think to cleanly do this is to either make a custom class to wrap or subclass vector. You could then produce a custom [] and at operators which throw an error on certain indexes. You could even have a deletion method which adds indeces to this list of banned ones.
Now if you need the error at compile time this is harder. I think something might be possible using a constexpr access operator and some static_asserts but I am not confident exactly how off hand.
This question already has answers here:
C++ Erase vector element by value rather than by position? [duplicate]
(4 answers)
Closed 7 years ago.
I would like to modify a member function of the vector class. Is this possible? For example I would like to be able to delete with respect to value, and not the integer of the vector.
I think this does what you are looking for. This example removes all the occurrences of the number 6 from a vector using std::remove. xs.erase is to make sure the vector removes the elements and shrinks the vector to the new size.
I generally avoid modifying the STL containers as the people who implemented them are likely far smarter than me when it comes to this kind of thing. I recommend you learn the standard library algorithms, there generally is one suited to most kinds of general container operations.
#include <iostream>
#include <algorithm>
int main(int argc, char** argv)
{
std::vector<int> xs{1, 3, 6, 2, 6, 5};
std::cout << "xs size: " << xs.size() << std::endl; // xs.size() == 6
auto value_to_remove = 6;
xs.erase(std::remove(xs.begin(), xs.end(), value_to_remove), xs.end());
for (const auto& x : xs)
std::cout << x << ", ";
std::cout << std::endl; // 1, 3, 2, 5,
std::cout << "xs size: " << xs.size() << std::endl; // xs.size() == 4
return 0;
}
In this case, as with most other STL algorithms value_to_remove can be replaced with a (unary) lambda predicate opening up a whole world of exotic value finding.
You could wrap the above in a function as follows:
template <typename T>
void erase_by_value(std::vector<T>& xs, const T& value_to_remove)
{
xs.erase(std::remove(xs.begin(), xs.end(), value_to_remove), xs.end());
}
I want to use a C++ STL container to implement Prim's algorithm. I need extract_max, find(element) and modify(element_value) functionality, but std::priority_queue only provides extract_max. Is there some other container that I can use? Obviously I want all of these to be as fast as possible.
Edit: The container should also provide functionality to modify the value of its element.
Push your elements in an std::set<T, std::greater<T>>, which is an ordered heap.
Call *set::begin() to get to the max element on O(1) or O(log(n)), depending on how set::begin() is implemented.
Use set::find to perform a search in O(log(n)).
To modify an element, you must unfortunately remove it from the set and then insert the modified version. (This also applies to make_heap and friends). There could exist an answer where this is not necessary, but (A) you'd have to be paranoid about what members are used for comparison vs equality, and (B) the difference in speed is very small. So there is no common container that works that way.
If the element ordering is not unique in it's ordering, use std::multiset instead, which is otherwise identical.
Example:
#include <iostream>
#include <set>
int main()
{
std::set<int, std::greater<int>> v { 3, 1, 4, 1, 5, 9 };
std::cout << "initially, v: ";
for (auto i : v) std::cout << i << ' ';
std::cout << '\n';
auto largest = *v.begin();
v.erase(v.begin());
std::cout << "largest element: " << largest << '\n';
std::cout << "after removing the largest element, v: ";
for (auto i : v) std::cout << i << ' ';
std::cout << '\n';
}
Live demo