the issue is I want to initialize a multiset iterator to some value, to be able to check later if there was some successful assignment to my iterator or not. Now without this initialization in some cycle of my program I get there some trash and all crashes.
In pseudocode I'd think about it like that:
multiset<whateverclassA,whateverclassB>::const_iterator init_me = NULL;
...//if succesfull, something is assigned to init_me iterator
if (init_me != NULL)
//do something
however it is not a usual pointer, so simple NULL doesn't suffice probably.
Any help appreciated!
Use std::multiset::end. This is also the value that will be returned by algorithms like std::multiset::find if the value could not be found:
multiset<whateverclassA,whateverclassB>::const_iterator
init_me = your_multiset.end();
/* ... */
if (init_me != your_multiset.end())
//do something
The variable init_me is an object instance, and NULL is a pointer. A non-pointer instance can not be compared to a pointer.
What you should to is set init_me to another iterator that means "no iterator", like end, and compare against that.
If the multiset in question always exists and is determined at the time you declare init_me (i.e. there is only one possible multiset that the iterator can point into), you could use mymultiset.end() as a marker.
(Note that this iterator does not point to the last element of a container, but to the "end", i.e. it is a special value. That's what makes it useful for flagging purposes. Be careful to only check other iterators against mymultiset.end(), not dereference it. Dereferencing end() or past-the-end iterators is undefined behaviour.)
Related
I'm trying to initialize an iterator to NULL, but it's not working. Can anyone help me?
If a pointer can be initialized with null, why can't we do that for an iterator?
vector<int> bob;
vector<int>::iterator it=NULL;
I want to initialize an iterator in a class constructor so that at the time of creation of an object of the class, the iterator should be set to NULL (default).
No, in general you cannot initialize an iterator with NULL. The iterator requirements do not require an iterator to be assignable or initializable from either an integer type or std::nullptr_t, the possible types that NULL can have.
There is no point in trying to do that. It is simply not needed. But since you have not explained why you would try to do that, I can't really make any further suggestions.
Regarding your further questions in the comments: You can value-initialize every forward iterator:
vector<int>::iterator it{}; // value-initialized
Since C++14 you are guaranteed that comparing iterators of the same type constructed in this way compare equal.
All container iterators are forward iterators.
The best equivalent to NULL or null_ptr for an iterator is the container::end() value. It likewise does not point to a valid element of the container. So, instead of testing the predicate (i == null_ptr), test (i == v.end()), and initialize as auto i = v.end();.
You can't initialize the iterator until after you have a container. But that is not a problem in practice because an iterator makes no sense without a container it refers to.
If you have complicated code that uses iterators, and you want to isolate that code in a function, you will have to pass two iterators to the function: the current or beginning iterator, and the end iterator. This is what the STL does.
An iterator is initialized when created.
You can null check its _Ptr member:
vector<int>::iterator p;
if (p._Ptr == NULL) ...
(using clang & dinkumware)
I am working on some C++ program right now and cannot resolve the above question. I see in forms this has been asked before, but neither answer was satisfying to me.
So, I am working with containers (e.g. a list), additionally I have an array with iterators to this list. I have been doing the following: Initially, I set all iterators in the array as pointing to a dummy list (DummyList.begin()).
To check, if the iterator was initialized I used to check (it != DummyList.begin()), in case needed I would then set the iterator to some element of the real list.
This seems to work.
However, when trying this for other contains (i.e. boost::circular_buffer), I got invalid iterator errors, and upon googling I found e.g. this comparing iterators from different containers, which says that comparing iterators from different containers produces undefined behavior.
That would be scary. Is this still the case?
If yes, then why did my program work so far?
And how would I do this otherwise then?
Edit:
The code looks something like this:
Initialization:
std::list<int> DummyList;
M = new std::list<int>::iterator[n + 1];
for (int i=0;i<=n;++i) {
M[i] = DummyList.begin();
}
Later than the check:
if (M[i] == DummyList.begin())
....
Yes, iterators can only be compared if they belong to the same container. Otherwise, the result is Undefined. Note that "appearing to work" is a valid form of Undefined Behaviour (and usually the worst one, as it hides errors).
What you can do in your case is use something like boost::optional to only store valid iterators in your array:
std::array<boost::optional<MyList::iterator>>, 10> iterators;
if (!iterators[i]) // iterator is not initialised
iterators[i] = myList.begin(); // store valid iterator
else
{
MyList::iterator it = *iterators[i]; // access valid iterator
iterators[i] = boost::none; // make iterator in array invalid again
}
I have a doubt regarding the generic algorithm copy in C++.
To copy from destination container ret and source container bottom,
copy(bottom.begin(), bottom.end(), back_inserter(ret));
works but
copy(bottom.begin(), bottom.end(), ret.end());
does not. Do these two statements have different implications?
Check what the statements do – there is no magic involved. In particular, copy is (essentially) just a loop. Simplified:
template <typename I>
void copy(I begin, I end, I target) {
while (begin != end)
*target++ = *begin++;
}
And back_inserter really does what the name says.
So in effect, without theback_inserter you do not expand the target container, you just write past its end: iterators don’t change their underlying container. The back_inserter function, on the other hand, creates a specialised iterator which does hold a reference to its original container and calls push_back when you dereference and assign to it.
In the first one you are giving copy a method of inserting, and from what container to insert from.
In the second one you are only giving a pointer to the end of the container.
Both return iterators, but...
ret.end() returns an iterator pointing to the end of the
container. It can be decremented, but not incremented (since it
already points to the end of the sequence), and it cannot be
dereferenced unless it is decremented (again, because it points
to one past the end of the sequence).
back_inserter(ret) is a function which returns
a back_insertion_iterator, which is a very special type of
"iterator" (category OutputIterator): it's incrementation
functions are no-ops, dereferencing it returns *this, and
assigning a value type to it calls push_back on the owning
container. (In other words, it's not an iterator at all, except
for the C++ standard; but it presents the interface of one to do
something very different.)
Is it dangerous to returning a pointer out of a std::map::find to the data and using that as opposed to getting a copy of the data?
Currently, i get a pointer to an entry in my map and pass it to another function to display the data. I'm concerned about items moving causing the pointer to become invalid. Is this a legit concern?
Here is my sample function:
MyStruct* StructManagementClass::GetStructPtr(int structId)
{
std::map<int, MyStruct>::iterator foundStruct;
foundStruct= myStructList.find(structId);
if (foundStruct== myStructList.end())
{
MyStruct newStruct;
memset(&newStruct, 0, sizeof(MyStruct));
myStructList.structId= structId;
myStructList.insert(pair<int, MyStruct>(structId, newStruct));
foundStruct= myStructList.find(structId);
}
return (MyStruct*) &foundStruct->second;
}
It would undoubtedly be more typical to return an iterator than a pointer, though it probably makes little difference.
As far as remaining valid goes: a map iterator remains valid until/unless the item it refers to is removed/erased from the map.
When you insert or delete some other node in the map, that can result in the nodes in the map being rearranged. That's done by manipulating the pointers between the nodes though, so it changes what other nodes contain pointers to the node you care about, but does not change the address or content of that particular node, so pointers/iterators to that node remain valid.
As long as you, your code, and your development team understand the lifetime of std::map values ( valid after insert, and invalid after erase, clear, assign, or operator= ), then using an iterator, const_iterator, ::mapped_type*, or ::mapped_type const* are all valid. Also, if the return is always guaranteed to exist, then ::mapped_type&, or ::mapped_type const& are also valid.
As for wise, I'd prefer the const versions over the mutable versions, and I'd prefer references over pointers over iterators.
Returning an iterator vs. a pointer is bad:
it exposes an implementation detail.
it is awkward to use, as the caller has to know to dereference the iterator, that the result is an std::pair, and that one must then call .second to get the actual value.
.first is the key that the user may not care about.
determining if an iterator is invalid requires knowledge of ::end(), which is not obviously available to the caller.
It's not dangerous - the pointer remains valid just as long as an iterator or a reference does.
However, in your particular case, I would argue that it is not the right thing anyway. Your function unconditionally returns a result. It never returns null. So why not return a reference?
Also, some comments on your code.
std::map<int, MyStruct>::iterator foundStruct;
foundStruct = myStructList.find(structId);
Why not combine declaration and assignment into initialization? Then, if you have C++11 support, you can just write
auto foundStruct = myStructList.find(structId);
Then:
myStructList.insert(pair<int, MyStruct>(structId, newStruct));
foundStruct = myStructList.find(structId);
You can simplify the insertion using make_pair. You can also avoid the redundant lookup, because insert returns an iterator to the newly inserted element (as the first element of a pair).
foundStruct = myStructList.insert(make_pair(structId, newStruct)).first;
Finally:
return (MyStruct*) &foundStruct->second;
Don't ever use C-style casts. It might not do what you expect. Also, don't use casts at all when they're not necessary. &foundStruct->second already has type MyStruct*, so why insert a cast? The only thing it does is hide a place that you need to change if you ever, say, change the value type of your map.
Yes,
If you build a generic function without knowing the use of it, it can be dangerous to return the pointer (or the iterator) since it can become un-valid.
I would advice do one of two:
1. work with std::shared_ptr and return that. (see below)
2. return the struct by value (can be slower)
//change the difination of the list to
std::map<int, std::shared_ptr<MyStruct>>myStructList;
std::shared_ptr<MyStruct> StructManagementClass::GetStructPtr(int structId)
{
std::map<int, std::shared_ptr<MyStruct>>::iterator foundStruct;
foundStruct = myStructList.find(structId);
if (foundStruct == myStructList.end())
{
MyStruct newStruct;
memset(&newStruct, 0, sizeof(MyStruct));
myStructList.structId= structId;
myStructList.insert(pair<int, shared_ptr<MyStruct>>(structId, shared_ptr<MyStruct>(newStruct)));
foundStruct= myStructList.find(structId);
}
return foundStruct->second;
Is there any way to check if an iterator (whether it is from a vector, a list, a deque...) is (still) dereferenceable, i.e. has not been invalidated?
I have been using try-catch, but is there a more direct way to do this?
Example: (which doesn't work)
list<int> l;
for (i = 1; i<10; i++) {
l.push_back(i * 10);
}
itd = l.begin();
itd++;
if (something) {
l.erase(itd);
}
/* now, in other place.. check if it points to somewhere meaningful */
if (itd != l.end())
{
// blablabla
}
I assume you mean "is an iterator valid," that it hasn't been invalidated due to changes to the container (e.g., inserting/erasing to/from a vector). In that case, no, you cannot determine if an iterator is (safely) dereferencable.
As jdehaan said, if the iterator wasn't invalidated and points into a container, you can check by comparing it to container.end().
Note, however, that if the iterator is singular -- because it wasn't initialized or it became invalid after a mutating operation on the container (vector's iterators are invalidated when you increase the vector's capacity, for example) -- the only operation that you are allowed to perform on it is assignment. In other words, you can't check whether an iterator is singular or not.
std::vector<int>::iterator iter = vec.begin();
vec.resize(vec.capacity() + 1);
// iter is now singular, you may only perform assignment on it,
// there is no way in general to determine whether it is singular or not
Non-portable answer: Yes - in Visual Studio
Visual Studio's STL iterators have a "debugging" mode which do exactly this. You wouldn't want to enable this in ship builds (there is overhead) but useful in checked builds.
Read about it on VC10 here (this system can and in fact does change every release, so find the docs specific to your version).
Edit Also, I should add: debug iterators in visual studio are designed to immediately explode when you use them (instead undefined behavior); not to allow "querying" of their state.
Usually you test it by checking if it is different from the end(), like
if (it != container.end())
{
// then dereference
}
Moreover using exception handling for replacing logic is bad in terms of design and performance. Your question is very good and it is definitively worth a replacement in your code. Exception handling like the names says shall only be used for rare unexpected issues.
Is there any way to check if a iterator (whether it is from a vector, a list, a deque...) is (still) dereferencable, i.e has not been invalidated ?
No, there isn't. Instead you need to control access to the container while your iterator exists, for example:
Your thread should not modify the container (invalidating the iterator) while it is still using an instantiated iterator for that container
If there's a risk that other threads might modify the container while your thread is iterating, then in order to make this scenario thread-safe your thread must acquire some kind of lock on the container (so that it prevents other threads from modifying the container while it's using an iterator)
Work-arounds like catching an exception won't work.
This is a specific instance of the more general problem, "can I test/detect whether a pointer is valid?", the answer to which is typically "no, you can't test for it: instead you have to manage all memory allocations and deletions in order to know whether any given pointer is still valid".
Trying and catching is not safe, you will not, or at least seldom throw if your iterator is "out of bounds".
what alemjerus say, an iterator can always be dereferenced. No matter what uglyness lies beneath. It is quite possible to iterate into other areas of memory and write to other areas that might keep other objects. I have been looking at code, watching variables change for no particular reason. That is a bug that is really hard to detect.
Also it is wise to remember that inserting and removing elements might potentially invalidate all references, pointers and iterators.
My best advice would be to keep you iterators under control, and always keep an "end" iterator at hand to be able to test if you are at the "end of the line" so to speak.
In some of the STL containers, the current iterator becomes invalid when you erase the current value of the iterator. This happens because the erase operation changes the internal memory structure of the container and increment operator on existing iterator points to an undefined locations.
When you do the following, iterator is incementented before it is passed to erase function.
if (something) l.erase(itd++);
Is there any way to check if an iterator is dereferencable
Yes, with gcc debugging containers available as GNU extensions. For std::list you can use __gnu_debug::list instead. The following code will abort as soon as invalid iterator is attempted to be used. As debugging containers impose extra overhead they are intended only when debugging.
#include <debug/list>
int main() {
__gnu_debug::list<int> l;
for (int i = 1; i < 10; i++) {
l.push_back(i * 10);
}
auto itd = l.begin();
itd++;
l.erase(itd);
/* now, in other place.. check if itd points to somewhere meaningful */
if (itd != l.end()) {
// blablabla
}
}
$ ./a.out
/usr/include/c++/7/debug/safe_iterator.h:552:
Error: attempt to compare a singular iterator to a past-the-end iterator.
Objects involved in the operation:
iterator "lhs" # 0x0x7ffda4c57fc0 {
type = __gnu_debug::_Safe_iterator<std::_List_iterator<int>, std::__debug::list<int, std::allocator<int> > > (mutable iterator);
state = singular;
references sequence with type 'std::__debug::list<int, std::allocator<int> >' # 0x0x7ffda4c57ff0
}
iterator "rhs" # 0x0x7ffda4c580c0 {
type = __gnu_debug::_Safe_iterator<std::_List_iterator<int>, std::__debug::list<int, std::allocator<int> > > (mutable iterator);
state = past-the-end;
references sequence with type 'std::__debug::list<int, std::allocator<int> >' # 0x0x7ffda4c57ff0
}
Aborted (core dumped)
The type of the parameters of the erase function of any std container (as you have listed in your question, i.e. whether it is from a vector, a list, a deque...) is always iterator of this container only.
This function uses the first given iterator to exclude from the container the element that this iterator points at and even those that follow. Some containers erase only one element for one iterator, and some other containers erase all elements followed by one iterator (including the element pointed by this iterator) to the end of the container. If the erase function receives two iterators, then the two elements, pointed by each iterator, are erased from the container and all the rest between them are erased from the container as well, but the point is that every iterator that is passed to the erase function of any std container becomes invalid! Also:
Each iterator that was pointing at some element that has been erased from the container becomes invalid, but it doesn't pass the end of the container!
This means that an iterator that was pointing at some element that has been erased from the container cannot be compared to container.end().
This iterator is invalid, and so it is not dereferencable, i.e. you cannot use neither the * nor -> operators, it is also not incrementable, i.e. you cannot use the ++ operator, and it is also not decrementable, i.e. you cannot use the -- operator.
It is also not comparable!!! I.E. you cannot even use neither == nor != operators
Actually you cannot use any operator that is declared and defined in the std iterator.
You cannot do anything with this iterator, like null pointer.
Doing something with an invalid iterator immediately stops the program and even causes the program to crash and an assertion dialog window appears. There is no way to continue program no matter what options you choose, what buttons you click. You just can terminate the program and the process by clicking the Abort button.
You don't do anything else with an invalid iterator, unless you can either set it to the begin of the container, or just ignore it.
But before you decide what to do with an iterator, first you must know if this iterator is either invalid or not, if you call the erase function of the container you are using.
I have made by myself a function that checks, tests, knows and returns true whether a given iterator is either invalid or not. You can use the memcpy function to get the state of any object, item, structure, class and etc, and of course we always use the memset function at first to either clear or empty a new buffer, structure, class or any object or item:
bool IsNull(list<int>::iterator& i) //In your example, you have used list<int>, but if your container is not list, then you have to change this parameter to the type of the container you are using, if it is either a vector or deque, and also the type of the element inside the container if necessary.
{
byte buffer[sizeof(i)];
memset(buffer, 0, sizeof(i));
memcpy(buffer, &i, sizeof(i));
return *buffer == 0; //I found that the size of any iterator is 12 bytes long. I also found that if the first byte of the iterator that I copy to the buffer is zero, then the iterator is invalid. Otherwise it is valid. I like to call invalid iterators also as "null iterators".
}
I have already tested this function before I posted it there and found that this function is working for me.
I very hope that I have fully answered your question and also helped you very much!
There is a way, but is ugly... you can use the std::distance function
#include <algorithms>
using namespace std
auto distance_to_iter = distance(container.begin(), your_iter);
auto distance_to_end = distance(container.begin(),container.end());
bool is_your_iter_still_valid = distance_to_iter != distance_to_end;
use erase with increment :
if (something) l.erase(itd++);
so you can test the validity of the iterator.
if (iterator != container.end()) {
iterator is dereferencable !
}
If your iterator doesnt equal container.end(), and is not dereferencable, youre doing something wrong.