Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
How can I translate a loop like the below one to C style?
for (auto element : vector) {
Do_Somethin();
}
You'd start with converting it to a non-ranged-based for loop.
{
auto&& range = Chains;
using std::begin; using std::end; // possibly cbegin/cend
auto it = begin(range); // possibly cbegin
auto end = end(range); // possibly cend
for(; it!=end; ++it) {
auto block = *it;
// body of loop
}
}
then you tease apart each piece.
Start by deducing what the auto variables are. Guess if you have to, then do a static_assert( std::is_same_v< decltype(begin), your_guess > ); to confirm. Once you have confirmed, replace. DO NOT guess and swap in the type and assume "it compiles, I got it right"; that can lead to subtle bugs.
Then replace begin and end with an equivalent expression. You'll have to do some research (it could be raw pointers into arrays, or it could be .begin methods, or it could be a free begin function in the namespace of the range expression).
What happens next depends on what your iterators are here. Are they plain pointers? If so, the problem is probably pretty easy. If not, you have more work to do.
Finally, remove all references, and then tidy up.
Ideally you'd want to do each of these steps as a git commit with unit tests confirming no change of behavior. You appear not to be qualified to make these changes without such testing. That is ok, and the unit testing will have value.
Going the other way, there are C++ to C translators. They will generate unreadable and unmaintainable code in practice.
But the output can be compiled by a C compiler.
Yes, you can always exchange ranged-for for a classic for loop.
For ranged-for to work, Chains must be of a type that implements an iterator interface, or must be an array.
If it's an array, you know what to do.
Otherwise, you can write the loop as:
for (auto it = Chains.begin(), end = Chains.end(); it != end; ++it)
{
auto block = *it;
Do_Somethin();
}
(Though, possibly, you may need cbegin() if only a const interface is available and begin() has no const overload for some reason.)
If the type of Chains supports random access with operator[], you could also try something like this:
for (std::size_t i = 0; i < Chains.size(); ++it)
{
auto block = Chains[i];
Do_Somethin();
}
… though you'll need to look at the documentation to find out what .size() should actually be.
Now of course C doesn't have iterators, or auto, but then it doesn't have classes either. You can choose to substitute replacements for those features as well if you like.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
This post was edited and submitted for review 7 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
for (auto& i : just_a_vec )
Or an iterator for loop.
for (std::vector<std::string>::iterator it = just_a_vec.begin(); it < just_a_vec.end(); it++)
Iterators predate range-based for loops, so they used to be the only of these two alternatives available. Nowadays, range-based for has mostly replaced iterators when dealing with a simple loop.
However, iterators can be used in various other contexts as well. For example, you can do std::sort(v.begin(), std::next(v.begin(), 5)) to sort the first five elements of a vector while leaving the rest of it alone.
Going back to iterating over a whole container:
If you can accomplish what you want with a range-based for, then it leads to more legible code, so they are preferable by default.
If you need iterators for some reason, such as using an algorithm that requires them, or because you need to jump ahead or back while iterating, then use those instead.
Also: In the later case, you can/should still use auto when declaring the iterator:
for(auto it = just_a_vec.begin(); it < just_a_vec.end(); it++) {
}
Edit: as asked: here's a simple, if a bit contrived, example where an iterator-based loop can still be useful:
// adds all values in the vector, but skips over twos values when encountering a 0
// e.g.: {1,2,0,4,5,2} => 5
int my_weird_accum(const std::vector<int>& data) {
int result = 0;
for(auto it = data.begin(); it != data.end(); ++it) {
auto v = *it;
result += v;
if(v == 0) {
// skip over the next two
assert(std::distance(it, data.end()) > 2);
std::advance(it, 2);
}
}
return 0;
}
Quick personal answer: Its somewhat sylistic and based on what version of c++ you are using. I typically prefer range based, but there are certainly moments iterators shine as well. Add both to your toolchest. For further reading.
Here is a list of other SO answers that get more into the performance and use cases.
What's the difference between iterator syntax in range-based loops for STL containers
Is the ranged based for loop beneficial to performance?
range based for loop vs regular iterator for loop
For further information. Google
Range vs iterator loop c++
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I struggle to understand what c++20 ranges add compared to good old fashioned iterators. Yes, I guess there is no need to use begin and end anymore, but simple overloads such as:
namespace std {
template <typename Container>
auto transform(Container&& container, auto&&... args) requires ( requires {container.begin(); container.end(); }) {
return transform(container.begin(), container.end(), args...);
}
}
would solve that problem.
Why are ranges useful and when should I use them compared to iterators?
EDIT: I know that ranges have other advantages over iterators (chaining, better methods etc...). However, these (I think?) can all be done with iterators and I don't understand why there was the need to introduce a whole new concept like ranges.
You have argued against your own conclusion, as evidenced here:
template <typename Container>
auto transform(Container&& container, auto&&... args)
requires ( requires {container.begin(); container.end(); }) {
So... what is this? It's a function which takes a template parameter that satisfies a constraint. Let's ignore that this constraint require member begin/end instead of the more reasonable std::ranges::begin/end requirements.
How many functions are you going to apply this requirement to? Probably lots. Every algorithm is going to have a version that has this requirement on it. So that's starting to look less like a one-off requirement and more like something that should be a named concept.
Especially since that concept should probably specify what kind of iterator the algorithm requires. You don't just need member begin/end; you need them to return an input_or_output_iterator and a sentinel_for that iterator:
requires ( requires(Container c)
{
{c.begin()} -> input_or_output_iterator;
{c.end()} -> sentinel_for<decltype(c.begin())>;
})
Do you really want to type this every time you ask for a "container"? Of course not; that's what named concepts are for.
So what is that concept? It's a thing over which you can iterate, a sequence of values that is accessible through a particular iterator interface.
And the name of that concept should probably be chosen so as not to imply ownership of the sequence of elements. The transform algorithm doesn't care if what it is given owns the sequence or not. So "container" is absolutely the wrong name.
So let's call this concept a rangevalue-sequence. Value-sequences can be iterated over through an iterator/sentinel interface. And you'll probably need to have different categories of value-sequences. Input sequences, forward sequences, contiguous sequences, etc. You maybe want to detect whether the sequence can compute a size in constant time, or whether the sequence is bounded or borrowed from its owner.
And wouldn't it be neat if you could write operators that create views of these value-sequences?
A range by any other name smells just as sweet. Once you start down the dark path of pairing iterators with sentinels, forever will it dominate your destiny.
Ranges are a natural concept when dealing with iterators. And everything built off of the range concepts is an outgrowth of that.
The point of most standard library core concepts, such as iterators, is to unify abstractions which are commonly made in the standard library. For iterators, this implies providing an interface for the commonly used concept of 'this points to an element in a container, and we want to be able to iterate over the container'.
The point of ranges then, is to hide the raw iterators from the public user interface. Very often when iterating, we need 2 pointers; both the start and end of our container. Ranges try to simplify this by hiding this interface, and providing a single interface for functions that operate on all between begin() and end().
In particular, range views would be the main reason to use ranges. They allow for easier to read code when you want to do function composition. The example from cppreference is a good example use:
#include <ranges>
#include <iostream>
int main()
{
auto const ints = {0,1,2,3,4,5};
auto even = [](int i) { return 0 == i % 2; };
auto square = [](int i) { return i * i; };
// "pipe" syntax of composing the views:
for (int i : ints | std::views::filter(even) | std::views::transform(square)) {
std::cout << i << ' ';
}
std::cout << '\n';
// a traditional "functional" composing syntax:
for (int i : std::views::transform(std::views::filter(ints, even), square)) {
std::cout << i << ' ';
}
}
When compared to raw iterators, ranges and views provide a higher-level abstraction layer at close to zero costs. In my personal opinion, in particular the 'view piping' is easier to read and more maintainable compared to the code one would write using c++ without ranges.
This question is a bump of a question that had a comment here but was deleted as part of the bump.
For those of you who can't see deleted posts, the comment was on my use of const char*s instead of string::const_iterators in this answer: "Iterators may have been a better path from the get go, since it appears that is exactly how your pointers seems be treated."
So my question is this, do iterators hold string::const_iterators hold any intrinsic value over a const char*s such that switching my answer over to string::const_iterators makes sense?
Introduction
There are many perks of using iterators instead of pointers, among them are:
different code-path in release vs debug, and;
better type-safety, and;
making it possible to write generic code (iterators can be made to work with any data-structure, such as a linked-list, whereas intrinsic pointers are very limited in this regard).
Debugging
Since, among other things, dereferencing an iterator that is passed the end of a range is undefined-behavior, an implementation is free to do whatever it feels necessary in such case - including raising diagnostics saying that you are doing something wrong.
The standard library implementation, libstdc++, provided by gcc will issues diagnostics when it detects something fault (if Debug Mode is enabled).
Example
#define _GLIBCXX_DEBUG 1 /* enable debug mode */
#include <vector>
#include <iostream>
int
main (int argc, char *argv[])
{
std::vector<int> v1 {1,2,3};
for (auto it = v1.begin (); ; ++it)
std::cout << *it;
}
/usr/include/c++/4.9.2/debug/safe_iterator.h:261:error: attempt to
dereference a past-the-end iterator.
Objects involved in the operation:
iterator "this" # 0x0x7fff828696e0 {
type = N11__gnu_debug14_Safe_iteratorIN9__gnu_cxx17__normal_iteratorIPiNSt9__cxx19986vectorIiSaIiEEEEENSt7__debug6vectorIiS6_EEEE (mutable iterator);
state = past-the-end;
references sequence with type `NSt7__debug6vectorIiSaIiEEE' # 0x0x7fff82869710
}
123
The above would not happen if we were working with pointers, no matter if we are in debug-mode or not.
If we don't enable debug mode for libstdc++, a more performance friendly version (without the added bookkeeping) implementation will be used - and no diagnostics will be issued.
(Potentially) better Type Safety
Since the actual type of iterators are implementation-defined, this could be used to increase type-safety - but you will have to check the documentation of your implementation to see whether this is the case.
Consider the below example:
#include <vector>
struct A { };
struct B : A { };
// .-- oops
// v
void it_func (std::vector<B>::iterator beg, std::vector<A>::iterator end);
void ptr_func (B * beg, A * end);
// ^-- oops
int
main (int argc, char *argv[])
{
std::vector<B> v1;
it_func (v1.begin (), v1.end ()); // (A)
ptr_func (v1.data (), v1.data () + v1.size ()); // (B)
}
Elaboration
(A) could, depending on the implementation, be a compile-time error since std::vector<A>::iterator and std::vector<B>::iterator potentially isn't of the same type.
(B) would, however, always compile since there's an implicit conversion from B* to A*.
Iterators are intended to provide an abstraction over pointers.
For example, incrementing an iterator always manipulates the iterator so that if there's a next item in the collection, it refers to that next item. If it already referred to the last item in the collection, after the increment it'll be a unique value that can't be dereferenced, but will compare equal to another iterator pointing one past the end of the same collection (usually obtained with collection.end()).
In the specific case of an iterator into a string (or a vector), a pointer provides all the capabilities required of an iterator, so a pointer can be used as an iterator with no loss of required functionality.
For example, you could use std::sort to sort the items in a string or a vector. Since pointers provide the required capabilities, you can also use it to sort items in a native (C-style) array.
At the same time, yes, defining (or using) an iterator that's separate from a pointer can provide extra capabilities that aren't strictly required. Just for example, some iterators provide at least some degree of checking, to assure that (for example) when you compare two iterators, they're both iterators into the same collection, and that you aren't attempting an out of bounds access. A raw pointer can't (or at least normally won't) provide this kind of capability.
Much of this comes back to the "don't pay for what you don't use" mentality. If you really only need and want the capabilities of native pointers, they can be used as iterators, and you'll normally get code that's essentially identical to what you'd get by directly manipulating pointers. At the same time, for cases where you do want extra capabilities, such as traversing a threaded RB-tree or a B+ tree instead of a simple array, iterators allow you to do that while maintaining a single, simple interface. Likewise, for cases where you don't mind paying extra (in terms of storage and/or run-time) for extra safety, you can get that too (and it's decoupled from things like the individual algorithm, so you can get it where you want it without being forced to use it in other places that may, for example, have too critical of timing requirements to support it.
In my opinion, many people kind of miss the point when it comes to iterators. Many people happily rewrite something like:
for (size_t i=0; i<s.size(); i++)
...into something like:
for (std::string::iterator i = s.begin; i != s.end(); i++)
...and act as if it's a major accomplishment. I don't think it is. For a case like this, there's probably little (if any) gain from replacing an integer type with an iterator. Likewise, taking the code you posted and changing char const * to std::string::iterator seems unlikely to accomplish much (if anything). In fact, such conversions often make the code more verbose and less understandable, while gaining nothing in return.
If you were going to change the code, you should (in my opinion) do so in an attempt at making it more versatile by making it truly generic (which std::string::iterator really isn't going to do).
For example, consider your split (copied from the post you linked):
vector<string> split(const char* start, const char* finish){
const char delimiters[] = ",(";
const char* it;
vector<string> result;
do{
for (it = find_first_of(start, finish, begin(delimiters), end(delimiters));
it != finish && *it == '(';
it = find_first_of(extractParenthesis(it, finish) + 1, finish, begin(delimiters), end(delimiters)));
auto&& temp = interpolate(start, it);
result.insert(result.end(), temp.begin(), temp.end());
start = ++it;
} while (it <= finish);
return result;
}
As it stands, this is restricted to being used on narrow strings. If somebody wants to work with wide strings, UTF-32 strings, etc., it's relatively difficult to get it to do that. Likewise, if somebody wanted to match [ or '{' instead of (, the code would need to be rewritten for that as well.
If there were a chance of wanting to support various string types, we might want to make the code more generic, something like this:
template <class InIt, class OutIt, class charT>
void split(InIt start, InIt finish, charT paren, charT comma, OutIt result) {
typedef std::iterator_traits<OutIt>::value_type o_t;
charT delimiters[] = { comma, paren };
InIt it;
do{
for (it = find_first_of(start, finish, begin(delimiters), end(delimiters));
it != finish && *it == paren;
it = find_first_of(extractParenthesis(it, finish) + 1, finish, begin(delimiters), end(delimiters)));
auto&& temp = interpolate(start, it);
*result++ = o_t{temp.begin(), temp.end()};
start = ++it;
} while (it != finish);
}
This hasn't been tested (or even compiled) so it's really just a sketch of a general direction you could take the code, not actual, finished code. Nonetheless, I think the general idea should at least be apparent--we don't just change it to "use iterators". We change it to be generic, and iterators (passed as template parameters, with types not directly specified here) are only a part of that. To get very far, we also eliminated hard-coding the paren and comma characters. Although not strictly necessary, I also change the parameters to fit more closely with the convention used by standard algorithms, so (for example) output is also written via an iterator rather than being returned as a collection.
Although it may not be immediately apparent, the latter does add quite a bit of flexibility. Just for example, if somebody just wanted to print out the strings after splitting them, he could pass an std::ostream_iterator, to have each result written directly to std::cout as it's produced, rather than getting a vector of strings, and then having to separately print them out.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Is it any nice way to call STL algorithms on an integer range?
For example I have a collection "col" with access to it's elements only via GetElement(int) method. Is it possible to use find_if function to find something in that collection?
I would like to call something like that:
auto element =
find_if(0, col.Size(), [&col] (int i) {
return predicate(col.GetElement(i));
});
I'm looking for an STL or any other library solution.
With standard C++? Yes, if you write a custom element iterator. Then, your code is easily simplified to:
auto element = find_if(col.begin(), col.end(), predicate);
It's not possible to do something closer to what you had in mind with the standard library, but it is with Boost, which is an incredible C++ library that you really ought to have. Boost has a counting iterator: http://www.boost.org/doc/libs/1_55_0/libs/iterator/doc/counting_iterator.html
How would you fill up a vector with the numbers zero through one hundred using std::copy()? The only iterator operation missing from builtin integer types is an operator*() that returns the current value of the integer. The counting iterator adaptor adds this crucial piece of functionality to whatever type it wraps. One can use the counting iterator adaptor not only with integer types, but with any incrementable type.
#include <boost\counting_iterator.hpp> //or something, not sure of exact header
int main() {
boost::counting_iterator<int> first(0);
boost::counting_iterator<int> last(col.Size());
auto element = find_if(first, last, [&col](int i) {return predicate(col.GetElement(i);});
}
Additionally, boost also has ranges. They don't really help you much in this exact situation, but it's related, so I'll mention it:
#include <boost\range\irange.hpp>
int main() {
for (int index: boost::range::irange<int>(0, col.Size()) )
{
std::cout << element; //counts from 0 to col.Size()
}
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
all
I am using vector in C++ STL to store my data. I pass and return them into and from functions. However, as the data size grows, the program is slower and slower. Thus I am updating the codes to an "iterator version".
What I want to archieve is that use iterators to pass, return and iterate STL vectors.
I am now ok with the operations with 1-dimensional vector, just like manipulating the arrays. However, when it comes to 2-dimensional vector, I am a bit confused.
Can anyone show me a simple code example that how to iterate a 2D vector using STL iterator?
Many thanks in advance.
Regards
Long
You state that your basic problem is performance, right?
You assume that this is caused due to copying.
Perhaps there could be simpler solutions for your problem:
Check if vectors can be passed by (const) reference
Check if shared_ptr makes sense
Consider if move semantics can help
Perhaps compiler version or implementation prevent return value optimization
If you need to know the size of a vector, and have two iterators it1 it2,
std::distance(it1, it2);
will tell you the distance between them. This will happen to be the size if they are begin and end
If you have a function like
int work(std::vector<int> items)
{
//...
}
this copies the vector items, so will use more RAM and take longer.
Sending a const ref instead will not copy the vector. Making it const stops you changing it, which might not help you, but you haven't posted any code so I don't know what you want to do.
int work(const std::vector<int> & items)
{
//...
}
Well its already somewhere on stackoverflow
But if you don't want to search here it is :
std::vector<std::vector<int> > vec{ {1,2,3},{4,5,6}};
//Simplest Way:- (C++11)
for(auto row:vec)
{
for(auto col:row)
std::cout<<col<< " ";
std::cout<<std::endl;
}
//OR Using iterator
std::vector<std::vector<int> >::iterator r;
std::vector<int>::iterator c;
for (r = vec.begin(); r != vec.end(); r++) {
for (c = r->begin(); c != r->end(); c++) {
std::cout<<*c<< " ";
}
std::cout<<std::endl;
}
Can get distance only between two iterators of same container
std::vector<int>::iterator s = v2.begin(); //Can be any start
std::vector<int>::iterator e = v2.end(); // Can be any end
std::cout<<"Distance :"<<std::distance(s,e)<<std::endl;