Short of (the obvious) building a C style string first then using that to create a std::string, is there a quicker/alternative/"better" way to initialize a string from a vector of chars?
Well, the best way is to use the following constructor:
template<class InputIterator> string (InputIterator begin, InputIterator end);
which would lead to something like:
std::vector<char> v;
std::string str(v.begin(), v.end());
I think you can just do
std::string s( MyVector.begin(), MyVector.end() );
where MyVector is your std::vector.
With C++11, you can do std::string(v.data()) or, if your vector does not contain a '\0' at the end, std::string(v.data(), v.size()).
std::string s(v.begin(), v.end());
Where v is pretty much anything iterable. (Specifically begin() and end() must return InputIterators.)
I like Stefan’s answer (Sep 11 ’13) but would like to make it a bit stronger:
If the vector ends with a null terminator, you should not use (v.begin(), v.end()): you should use v.data() (or &v[0] for those prior to C++17).
If v does not have a null terminator, you should use (v.begin(), v.end()).
If you use begin() and end() and the vector does have a terminating zero, you’ll end up with a string "abc\0" for example, that is of length 4, but should really be only "abc".
Just for completeness, another way is std::string(&v[0]) (although you need to ensure your string is null-terminated and std::string(v.data()) is generally to be preferred.
The difference is that you can use the former technique to pass the vector to functions that want to modify the buffer, which you cannot do with .data().
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());
Related
I want to convert part of a vector to a string, I found this
std::string myString(Buffer.begin(), Buffer.end()); (Buffer is the vector)
But here I converted the whole vector. What the easiest way if I want to skip first 5 chars of the vector and convert the rest? Like ''.join(Buffer[5::]) if it was python.
Just add your offset to begin. Since a vector has random access iterators, you can just use
std::string myString(Buffer.begin() + 5, Buffer.end());
If you are not sure about what type of iterators your container is using, you can use std::next like
std::string myString(std::next(Buffer.begin(), 5), Buffer.end());
which will handle all iterator types, it also may be an O(N) operation.
You also need to make sure that the size of the container is at least 5 before you do this otherwise you'll have undefined behavior if the container is too small.
Like this for example:
if (Buffer.size() >= 5) {
std::string myString(
Buffer.begin() + 5,
Buffer.end());
A more general approach that works with non-random access iterators as well (such as iterators of std::list for example):
std::string myString(
std::next(Buffer.begin(), 5),
Buffer.end());
Or using ranges:
auto subrange = Buffer | std::ranges::views::drop(5);
std::string myString(
std::ranges::begin(subrange),
std::ranges::end(subrange));
A safe (avoiding accesses out of bounds), general approach could be
std::string myString(std::next(Buffer.cbegin(), std::min(5, Buffer.size()),
Buffer.cend()); // ^^^^^^^^^^^^^^^^^^^^^^^^^
I need to convert a std::array to a std::vector, but I could not find anyway to do it quickly. Here is the sample code:
std::array<char,10> myData={0,1,2,3,4,5,6,7,8,9};
Now I need to create a vector such as:
std::vector<char> myvector;
and initialize it with the array values.
What is the fastest way to do this?
You can use the constructor of std::vector taking iterators.
Constructs the container with the contents of the range [first, last).
e.g.
std::array<char,10> myData = {0,1,2,3,4,5,6,7,8,9};
std::vector<char> myvector(myData.begin(), myData.end());
Just for variety:
std::vector<char> myvector(std::begin(myData), std::end(myData);
std::vector<char> myvector { myData.begin(), myData.end() };
I'd use the range constructor of vector - looking like myvector(myData.begin(), myData.end())
for future reference:
http://en.cppreference.com/w/cpp/container/vector/vector
I want to sort a vector using sort algorithm in C++.
str is the name of std::vector<int> I want to sort.
What's the difference between this:
std::sort(str.rend(),str.rbegin())
and this:
std::sort(str.begin(),str.end())
Assuming you intend to use std::sort to sort the string (since neither std::vector nor std::string have a sort method), the first statement is incorrect and leads to undefined behaviour (UB):
std::sort(str.rend(),str.rbegin());
Here, std::sort will attempt to dereference str.rend(), which is a "past the end" iterator. De-referencing such an iterator is UB.
A correct use of reverse iterators would be
std::sort(str.rbegin(),str.rend());
This would result in the string/vector being sorted in descending order.
The iterators in the standard library on lots of containers and other things (like std::string) have a reverse variety which begin with r (rbegin(), rend and the like). These will iterate in the reverse-sequential order. Using just begin and end will sort your string in the correct format from start to finish.
Try to avoid using the reverse iterators and just use the regular begin() and end() on your strings:
std::string str = "bacd";
std::sort( str.begin(),str.end() );
std::cout << str << std::endl; // should produce "abcd" on your output, without quotes
Edit:
So... you want vector<int> to be sorted instead? If so, do the same as above, except call std::sort with the begin() and end() of your std::vector<int>.
I guess this is a simple question. I need to do something like this:
std::set<int> s1, s2;
s1 = getAnExcitingSet();
std::transform(s1.begin(), s1.end(), std::back_inserter(s2), ExcitingUnaryFunctor());
Of course, std::back_inserter doesn't work since there's no push_back.
std::inserter also needs an iterator? I haven't used std::inserter so I'm not sure what to do.
Does anyone have an idea?
Of course, my other option is to use a vector for s2, and then just sort it later. Maybe that's better?
set doesn't have push_back because the position of an element is determined by the comparator of the set. Use std::inserter and pass it .begin():
std::set<int> s1, s2;
s1 = getAnExcitingSet();
transform(s1.begin(), s1.end(),
std::inserter(s2, s2.begin()), ExcitingUnaryFunctor());
The insert iterator will then call s2.insert(s2.begin(), x) where x is the value passed to the iterator when written to it. The set uses the iterator as a hint where to insert. You could as-well use s2.end().
In 2016 there was a proposal to have a "single argument inserter iterator".
https://isocpp.org/files/papers/p0471r0.html . I couldn't find if it the proposal advanced. I think it makes sense.
For now you can have this behavior defining the maker function:
template<class Container>
auto sinserter(Container& c){
using std::end;
return std::inserter(c, end(c));
}
Used as:
std::transform(begin(my_vec), end(my_vec), sinserter(my_set), [](auto& e){return e.member;});
So, I wrote a bunch of code that accesses elements in an stl vector by index[], but now I need to copy just a chunk of the vector. It looks like vector.insert(pos, first, last) is the function I want... except I only have first and last as ints. Is there any nice way I can get an iterator to these values?
Try this:
vector<Type>::iterator nth = v.begin() + index;
way mentioned by #dirkgently ( v.begin() + index ) nice and fast for vectors
but std::advance( v.begin(), index ) most generic way and for random access iterators works constant time too.
EDIT
differences in usage:
std::vector<>::iterator it = ( v.begin() + index );
or
std::vector<>::iterator it = v.begin();
std::advance( it, index );
added after #litb notes.
Also; auto it = std::next(v.begin(), index);
Update: Needs a C++11x compliant compiler
You can always use std::advance to move the iterator a certain amount of positions in constant time:
std::vector<int>::iterator it = myvector.begin();
std::advance(it, 2);
Actutally std::vector are meant to be used as C tab when needed. (C++ standard requests that for vector implementation , as far as I know - replacement for array in Wikipedia)
For instance it is perfectly legal to do this folowing, according to me:
int main()
{
void foo(const char *);
sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');
foo(&vec[0]);
}
Of course, either foo must not copy the address passed as a parameter and store it somewhere, or you should ensure in your program to never push any new item in vec, or requesting to change its capacity. Or risk segmentation fault...
Therefore in your exemple it leads to
vector.insert(pos, &vec[first_index], &vec[last_index]);