`std::forward_list` walk until iterator is null? - c++11

Is it possible to walk a std::forward_list, incrementing an iterator, until said interator is null? The old-fashioned way...
In the following example, I create a print() function.
#include <iostream>
#include <forward_list>
void print(std::forward_list<int>::iterator fl_it, std::forward_list<int>::iterator e) {
while (fl_it != e) {
std::cout << *fl_it << ' ';
++fl_it;
}
std::cout << std::endl; //-> 1 2 3
}
int main() {
std::forward_list<int> fl = {1, 2, 3};
print(fl.begin(), fl.end());
std::cout << std::endl;
return 0;
}
Notice how passing an iterator pointing to the end of the list is necessary, so that we know when to stop walking.
What I want to do is simply pass an iterator to the head of the list, and step along until there are no more elements, like so:
void print(std::forward_list<int>::iterator fl_it) {
while (fl_it != nullptr) {
std::cout << *fl_it << ' ';
++fl_it;
}
std::cout << std::endl;
}
My compiler doesn't like this fl_it != nullptr business.
My first inclination was to look for a method to check if the iterator is null, and references the end of the list. Sadly, such a method does not exist.
Any ideas?

You don't.
std::forward_list is a standard library container. Like all containers, it goes from begin to end. There are no "null" iterators. Operations therefore are on a range of iterators.
Note that the Range TS proposal intends to allow "sentinel" types instead of requiring end iterators. A single sentinel could compare equal to the end iterator of any range. So forward_list could indeed be updated to have such a value.
But it still wouldn't be a "null" iterator.

You should realise that the iterator object is not exactly a pointer. It is an object and it represents the position of an item in a datastructure.
Also incrementing the end iterator does not result in a null iterator. It is undefined behavior. Look at Can an STL map iterator go out of bounds through incrementing?

The iterator is not null when at the end of the list, instead it is equal to the list's end iterator fl.end(). So both iterators need to be passed to the function.
The internal implementation of the iterator depends on the STL library used, for std::forward_list its interface is such that it fulfills the ForwardIterator concept: http://en.cppreference.com/w/cpp/concept/ForwardIterator .

Related

Using .sum() and += on std::valarray<T>

I am using the type std::valarray<std::valarray<double>> and wish to sum each of the contained valarrays element wise, to leave a std::valarray<double>.
The C++ documentation states that the operator .sum() can be applied to std::valarray<T> so long as the operator += is defined for type T. My code below (method1) tries to apply this to std::valarray<std::valarray<double>>, but the result appears to be nonsense.
However if I perform this manually, using the += operator (method2), I get the result I want. But the fact that method2 works seems to imply that the operator += is defined for the type std::valarray<double>, and hence that method1, using .sum(). should work. I really can't understand what is happening here...
My code:
#include <iostream>
#include <valarray>
// Attempt to use .sum() operator
std::valarray<double> method1(const std::valarray<std::valarray<double>>& data) {
return data.sum();
}
// Manual summation using += operator
std::valarray<double> method2(const std::valarray<std::valarray<double>>& data) {
std::valarray<double> sum(data[0].size());
for (size_t i{0}; i < data.size(); i++) {
sum += data[i];
}
return sum;
}
// Display size and elements
void showData(const std::valarray<double> data) {
std::cout << "Size = " << data.size() << "\n";
std::cout << "Data = ";
for (size_t i{0}; i < data.size(); i++) {
std::cout << data[i] << " ";
}
std::cout << "\n\n";
}
int main() {
std::valarray<std::valarray<double>> data{{1,2},{3,4}};
showData(method1(data));
showData(method2(data));
}
My output:
Size = 0
Data =
Size = 2
Data = 4 6
The sum method of std::valarray requires operator+= to be defined for its value type (in your case, std::valarray), but std::valarray also requires it to be default-constructible (from the "Numeric" concept requirement).
This allows the sum method to work without operator+, by first default-constructing an element, and then adding each contained element with operator+=.
Although it isn't defined anywhere, as far as I know, it probably works something like this.
T sum() const {
T result;
for (auto& it : elements) {
result += it;
}
return result;
}
The problem with a valarray of valarrays (std::valarray<std::valarray>) is that a default-constructed valarray is empty. And when operator+= is applied with an empty valarray and a non-empty one, it results in undefined behavior ("The behavior is undefined if size() != v.size()"). What you are likely to get is an empty valarray as a result (but you could potentially get anything).
What you could use instead is std::accumulate. It requires an initial value as third parameter, which takes care of the problem.
std::accumulate(std::begin(data), std::end(data), std::valarray<double>(data[0].size()))
Live on Coliru.
PS: don't ask me why std::valarray has no method begin and end.

Why this is an infinite loop

i have declared a map below using stl and inserted some values in it.
#include<bits/stdc++.h>
int main()
{
map<int,int> m;
m[1]=1;
m[2]=1;
m[3]=1;
m[4]=1;
m[5]=1;
m[6]=1;
for(auto it=m.begin();it!=m.end();)
{
cout<<it->first<<" "<<it->second<<endl;
it=it++;
}
return 0;
}
When i executed the above written code it ended up in an infinite loop. Can someone tell me why it does so?
I am incrementing the value of iterator it and then it gets stored in it which should get incremented next time the loop is executed and eventually it should terminate normally.Am i wrong?
The bad line is it = it++;. It is undefined behavior! Because it is not defined, when it is increased, in your case it is increased before the assingment to itsself again, that the value of it before it is increased is assigned to it again and so it keeps at the first position. The correct line would be it = ++it; or only ++it;/it++;, because it changes itsself.
Edit
That is only undefined with the builtin types, but in here that is defined by the source-code of the map in the stl.
If you try doing something similar with an int, you'll get a warning:
int nums[] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < sizeof nums / sizeof *nums; ) {
cout << nums[i] << '\n';
i = i++;
}
warning: operation on 'i' may be undefined [-Wsequence-point]
However, when you're using a class (std::map::iterator) which has operator overloading, the compiler probably isn't smart enought to detect this.
In other words, what you're doing is a sequence point violation, so the behavior is undefined behavior.
The post-increment operation would behave like this:
iterator operator ++ (int) {
auto copy = *this;
++*this;
return copy;
}
So, what happens to your increment step is that iterator it would get overwritten by the copy of its original value. If the map isn't empty, your loop would remain stuck on the first element.

Unexpected value returned by use_count() of shared_ptr while retrieving from vector

The program below is outputting unexpected use_count() value when shared pointer is printed using iterator de-reference of std::vector:
#include<iostream>
#include<memory>
#include<vector>
class A;
typedef std::shared_ptr<A> sharedPtr;
typedef std::vector<sharedPtr> sharedPtrVect;
typedef sharedPtrVect::const_iterator vectItr;
class A
{
public:
A(int inp): m_Val(inp) { /*std::cout << "*** A ctor called: " << m_Val << " ***" <<std::endl;*/ }
~A() { /*std::cout << "### A dtor called: " << m_Val << " ###" <<std::endl; */}
int getVal() const { return m_Val; }
private:
int m_Val;
};
int main()
{
sharedPtrVect myVect1, myVect2;
vectItr myVectItr;
std::shared_ptr<A> tmpPtr;
for(int i = 1 ; i <= 5 ; i++ ) {
std::cout << "Pushed back: " << i << std::endl;
tmpPtr = std::make_shared<A>(i);
myVect1.push_back(tmpPtr);
}
myVectItr = myVect1.begin();
for( ; myVectItr != myVect1.end() ; ++myVectItr) {
std::cout << "-----------------------------" << std::endl;
std::cout << "Element number: " << (*myVectItr).get()->getVal() << std::endl;
std::cout << "Element use count: " << (*myVectItr).use_count() << std::endl;
std::cout << "-----------------------------" << std::endl;
}
return 0;
}
The output of the above code is:
Pushed back: 1
Pushed back: 2
Pushed back: 3
Pushed back: 4
Pushed back: 5
-----------------------------
Element number: 1
Element use count: 1
-----------------------------
-----------------------------
Element number: 2
Element use count: 1
-----------------------------
-----------------------------
Element number: 3
Element use count: 1
-----------------------------
-----------------------------
Element number: 4
Element use count: 1
-----------------------------
-----------------------------
Element number: 5
Element use count: 2 //I am not sure why or how this is 2?
-----------------------------
I don't understand how the use_count() for the last vector element is 2. Shouldn't it be 1 like others? I am not creating any copies of the shared pointer stored in the last element of the vector.
What am I missing here?
EDIT: I have good experience in C++98, but less experience in C++11.
Shouldn't it be 1 like others? I am not creating any copies of the shared pointer stored in the last element of the vector. What am I missing here?
But you are creating a copy. You push_back() from tmpPtr. push_back() puts a copy of its argument into the vector, unless you tell it to move instead. (More on that later!)
Therefore, what happens for all but the last element is this:
tmpPtr holds the only reference to the shared resource
You push_back() a copy, so the copy-constructor of shared_ptr increments the use count to 2
You then assign the next element to tmpPtr, releasing the reference to, and thereby decrementing the use count of, the previous element's resource.
But, of course, there is no subsequent assignment on the last iteration of the loop. So, at the point of printing, tmpPtr is still in scope, and it retains a reference to the last resource that was allocated. Hence the 1-higher refcount on the last element. This seems perfectly expected to me. ;)
To see the results you expected, you need to either destroy tmpPtr after you copy it but before you print, or simply avoid the copy from it in the first place. The former could be done by moving its declaration into the for loop, as SirGuy pointed out in the comments.
However, clearly, the latter is superior. How do we do that? Well, C++11 lets us move instead. So, you could emplace_back( std::move(tmpPtr) ), in which the move will cast to an rvalue and thus invoke the move-constructor of the vector element. This will cause tmpPtr to release its reference upon being moved into the vector, effectively ensuring the use count is always 1. This leaves tmpPtr (like any moved-from object) in a valid-but-unspecified state, i.e. useful only to be reassigned-to.
(Note: push_back() will achieve the same thing, but I generally prefer using emplace_back() wherever possible, as it's more efficient in other situations, so it's a better default.)
Of course, you can then combine both of these: declare tmpPtr within the scope of the for loop, and move from it. However... you don't even need tmpPtr at all! It does not appear to serve any useful purpose. So, you could just not use it, and instead directly emplace_back() the result of make_shared(). Because the return value thereof will be an rvalue, it will implicitly be moved into the vector; no cast by std::move is needed.

C++11 set range based for using structs as elements

Let's say I have a struct like this:
struct Something{
string name;
int code;
};
And a set of Something type:
set<Something> myset;
myset.insert({"aaa",123,});
myset.insert({"bbb",321});
myset.insert({"ccc",213});
What's wrong with this?
for (auto sth : myset){
cout << sth.name;
cout << sth.code;
}
Along the same lines... why can't I modify an element (even when the set contains plain int items) using something like this?
for (auto &sth : myset){
sth=[some value];
}
I know I can do this with vectors and maps. Why not sets?
Thanks!
Modifying an element of a set implies its position in the set's order can change. Because your compiler cannot know what exactly a particular set uses to determine its element's orders. Well, it could, theoretically, but even then it would be nearly impossible to keep track of the rearrangements while iterating through the container. It would make no sense.
What you can do, if you want to modify the elements of a set in such a way that you know will not change their order in a set, you can make the non-ordering members of your struct mutable. Note that if you make a mistake and the set's order is disturbed, any other operations on the set (like a binary search) will give incorrect results after that faulty modification. If you don't want to make members mutable, const_cast is an option, with the same caveats.
To elaborate on my answer above, an example:
#include <iostream>
#include <set>
struct bla
{
std::string name;
int index;
};
bool operator<(const bla& left, const bla& right) { return left.index < right.index; }
int main()
{
std::set<bla> example{{"har", 1}, {"diehar", 2}};
// perfectly fine
for(auto b : example)
std::cout << b.index << ' ' << b.name << '\n';
// perfectly fine - name doesn't influence set order
for(auto& b : example) // decltype(b) == const bla&
const_cast<std::string&>(b.name) = "something";
// better than first loop: no temporary copies
for(const auto& b : example)
std::cout << b.index << ' ' << b.name << '\n';
// using a "universal reference auto&&", mostly useful in template contexts
for(auto&& b : example) // decltype(b) == const bla&
std::cout << b.index << ' ' << b.name << '\n';
// destroying order of the set here:
for(auto& b : example)
const_cast<int&>(b.index) = -b.index;
// anything here relying on an ordered collection will fail
// This includes std::set::find, all the algorithms that depend on uniqueness and/or ordering
// This is pretty much all that will still work, although it may not even be guaranteed
for(auto&& b : example)
std::cout << b.index << ' ' << b.name << '\n';
}
Live code on Coliru.
Note the first const_cast is only ok because the underlying example isn't const in the first place.

what's the difference between *iter.first and iter->first?

vector<int> a = { 1,2,3,4,5,6,7 };
pair<vector<int>, vector<int>::iterator> pair_of_itr; //not working showing wrong directional error!
auto pair_of_itr = minmax_element(a.begin(), a.end());
cout << *pair_of_itr.first << " " << *pair_of_itr.second << endl; // working with auto but not with the PAIR of iterator.
//cout << pair_of_itr->first << " " << pair_of_itr->second << endl // not working
return 0;
here i have explained via comments. plz do refer comments.
a->b is the same as (*a).b. *a.b is the same as *(a.b). So they differ in whether a is dereferenced, or a.b is dereferenced.
In your case, auto pair_of_itr = std::minmax_element ... creates a std::pair of iterators, and it is the iterator you want to dereference. So that would be *pair_of_itr.first. *pair_of_itr is ill-formed because a std::pair is not itself a pointer or iterator.
The problem with pair<vector<int>, vector<int>::iterator> pair_of_itr; is simply that the first element of the pair is a std::vector, not a std::vector::iterator. So in that case neither pair_of_itr nor pair_of_itr.first can be dereferenced. *pair_of_itr.second would compile, because the second element is an iterator.
It's usually a good idea to add redundant parentheses, particularly if you needed to ask whether they were necessary. Other people also might not remember that *a.b means *(a.b), and the parentheses don't cost a lot.

Resources