Why vector.clear() in c++ retain value in vector? [duplicate] - c++

This question already has answers here:
Vector going out of bounds without giving error
(4 answers)
Why is the phrase: "undefined behavior means the compiler can do anything it wants" true?
(2 answers)
Closed last month.
I found that, vector.clear() does retain value.
Vector.clear() retain values which can be accessed through vector[index]. But if I do, for(auto &i:vector) { cout <<a;} then, it doesn't disclose any values. What is the reason of that ?

Accessing a vector out of bounds leads to undefined behavior. It may "work." Or maybe not. There is no guarantee.
From the operator[] documentation at cppreference.com:
Notes
Unlike std::map::operator[], this operator never inserts a new element into the container. Accessing a nonexistent element through this operator is undefined behavior.
If you want bounds checking on a std::vector use at rather than operator[].

The elements have been marked as cleared, this does not necessarily mean they are gone. When you access via vec[1] you are entering the fields of undefined behaviour.
If you were to try vector.at(1), your program would correctly raise an std::out_of_range exception.
The reason your for (auto &i : vec) loop is empty, is that it calls .begin() and .end() on your vector, and that range is empty since these iterators are equal after a .clear()

Related

What does end() refere to in the following example? [duplicate]

This question already has an answer here:
Behavior when dereferencing the .end() of a vector of strings
(1 answer)
Closed last year.
I have a list of sets:
std::list<std::set<int>> nn = {{1,2},{4,5,6}};
and I want to print out the element which end() refers to:
for (auto el : nn){
std::cout << *el.end() << std::endl;
}
What I get as a result is:
2 and 3.
I do not know where do these values come from. Can someone help me plz?
Question 1
What does end() refere to
Answer
end() is a public member function of std::set that returns an iterator to the past-the-end element in the set container.
Question 2
I do not know where do these values come from.
Answer
When you wrote:
std::cout << *el.end() << std::endl;//this is undefined behavior
In the above statement you are dereferencing the iterator that was returned by the end() member function.
But note that if we dereference the iterator that was returned by this member function then we get undefined behavior.
Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior.
1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.
It is not allowed to de-reference the end() iterator. Doing so causes undefined behavior. It doesn't refer to any element of the container, but one past the last element.
The reason that end() "points" after the last element, is that it is necessary to distinguish empty containers. If end() was referring to the last element and begin() to the first, then if begin() == end() that would mean that there is one element in the container and we can't distinguish the case of an empty container.
For containers that support it, to access the last element of the container you can use .back(), which will return a reference, not an iterator. But this is only allowed if there is a last element, i.e. if the container is not empty. Otherwise you have again undefined behavior. So check .empty() first if necessary.
std::set does not have the back() member and is not really intended to be used this way, but if you really want to access the last element, which is not the last element in the constructor initializer list, but the last element in the < order of the elements, then you can use std::prev(el.end()) or el.rbegin() ("reverse begin") which will give you an iterator to the last element. Again, dereferencing this iterator is only allowed if the container is not empty. (For std::prev forming the iterator itself isn't even allowed if the container is empty.)
Undefined behavior means that you will have no guarantees on the program behavior. It could output something in one run and something else in another. It could also output nothing, etc.
There is no requirement that you will get the output you see. For example, current x86_64 Clang with libc++ as standard library implementation, compiles (with or without optimization) a program that prints 0 twice. https://godbolt.org/z/nWMss1fqe
Practically speaking, assuming the compiler didn't take advantage of the undefined behavior for an optimization that drastically changes the program from the "intended" program flow, you will likely, depending on the implementation of the standard library, read some internal memory of the std::set implementation in the standard library, get a segmentation fault if the indirection points to inaccessible memory or incidentally (with no guarantees) refer to other values in the container.

C++ what happen to reference when a vector resize its capacity? [duplicate]

This question already has answers here:
Does resizing a vector invalidate iterators?
(5 answers)
Closed 4 years ago.
Let's assume we have a reference to an element in a vector. (I'm not sure about what happen behind reference, but I guess the reference holds the pointer to the exact element.)
And we keep pushing things into that vector, then it reach its capacity, then resize itself. What happen in resizing is that it might ask for a new space in the memory, and then copy the original data to the new space. And now the memory which the reference point to become undefined.
I'm not sure if my guess is right. Could this happen? Or my understanding is wrong.....If that's the case, then using reference to container's element might be dangerous...
You are correct, when vector capacity is increased, new memory is allocated and all references/pointers/iterators to the vector elements are invalidated.

Result of invalid iterator passed to std::unordered_set::erase()

std::unordered_set::erase() has 3 overloads: In the one taking a reference, passing an "invalid" value, i.e. one that doesn't exist in the set, simply makes erase() return 0. But what about the other two overloads?
Does the C++11 standard say what erase() should do in this case, or it's compiler dependent? Is it supposed to return end() or undefined behavior?
I couldn't find an answer in the specification, cppreference.com, cplusplus.com. On IBM site they say it returns end() if no element remains after the operation, but what happens if the operation itself fails due to an invalid iterator?
And in general, do erase() methods for STL containers simply have undefined behavior in these case?
(so I need to check my iterators before I pass any to erase(), or use the unordered_set::erase() overload which takes a value_type reference, which would simply return 0 if it fails)
There is a big semantic difference between trying to remove a value that doesn't occur in set and trying to erase from a invalid iterator.
Trying to use an invalid iterator is undefined behaviour and will end badly.
Do you have a specific use-case you are thinking of when you might want to erase an invalid iterator?
These are two completely different cases. There is no "invalid value", values that don't exist in the set are still valid. So you pass a valid value that s not contained in the set and thus get 0 returned - no elements have been erased.
The other overloads are completely different. The standard requires the iterators passed to the erase methods to be "valid and dereferencable" and "a valid iterator range", respectively. Otherwise the behavior is undefined.
So yes, iterators have to be valid. But you cannot check if an iterator is valid programmatically - you have to make sure from your program logic, that they are.

Access violation when assigning an uninitialized iterator

I have a problem with assigning an unintialized to an initialized iterator. The following code excerpt produces an access violation when built with Visual Studio 2010. In previous versions of Visual Studio the code should work.
#include <list>
int main() {
std::list<int> list;
std::list<int>::iterator it = list.begin();
std::list<int>::iterator jt;
it = jt; // crashes in VS 2010
}
Wouldn't this be considered valid C++?
I need this code to implement a "cursor" class that either points nowhere or to a specific element in a list. What else could I use as a value for an uninitialized iterator if I don't have a reference to my container yet?
it = jt; // crashes in VS 2010
This invokes undefined behaviour (UB). According to the C++ Standard ,jt is a singular iterator which is not associated with any container, and results of most expressions are undefined for singular iterator.
The section ยง24.1/5 from the C++ Standard (2003) reads (see the bold text specifically),
Just as a regular pointer to an array
guarantees that there is a pointer
value pointing past the last element
of the array, so for any iterator type
there is an iterator value that points
past the last element of a
corresponding container. These values
are called past-the-end values. Values
of an iterator i for which the
expression *i is defined are called
dereferenceable. The library never
assumes that past-the-end values are
dereferenceable. Iterators can also
have singular values that are not
associated with any container.
[Example: After the declaration of an
uninitialized pointer x (as with int*
x;), x must always be assumed to have
a singular value of a pointer.]
Results of most expressions are
undefined for singular values; the
only exception is an assignment of a
non-singular value to an iterator that
holds a singular value. In this case
the singular value is overwritten the
same way as any other value.
Dereferenceable values are always
nonsingular.
If MSVS2010 crashes this, it is one of infinite possibilities of UB, for UB means anything could happen; the Standard doesn't prescribe any behavior.
C++11, 24.2.1/3:
Results of most expressions are undefined for singular values; the
only exceptions are destroying an iterator that holds a singular
value, the assignment of a non-singular value to an iterator that
holds a singular value, and, for iterators that satisfy the
DefaultConstructible requirements, using a value-initialized iterator
as the source of a copy or move operation.
The list is limitative, and your example isn't listed in the allowed exceptions. jt is singular and default-initialized. Therefore it may not be used as the source of a copy operation.
You need a KNOWN value to use a signal. You don't have that unless you have a container to get .end() from, which you think is your problem.
What you really need to do is get away from thinking that you can use 'special' iterator values for oddball cases that don't involve a container. Iterators, while they work a lot like pointers, are NOT pointers. They don't have the equivalent of 'NULL'.
Instead, use a boolean flag value to see if the container is set or not, and make sure the iterators (all of them, if you have more than one) get set to some valid value when the container becomes known, and the flag gets set back to false when you lose the container. Then you can check the flag before any iterator operations.
list.end() points anywhere beyond the container, so we can consider it like pointing nowhere.
Also accessing unitialized variable causes undefined behavior.

Does passing an empty range (identical iterators) to an STL algorithm result in defined behavior?

Consider the following:
std::vector<int> vec(1); // vector has one element
std::fill(vec.begin(), vec.begin(), 42);
std::fill(vec.begin()+1, vec.end(), 43);
std::fill(vec.end(), vec.end(), 44);
Will all of the std::fill usages above result in defined behavior? Am I guaranteed that vec will remain unmodified? I'm inclined to think "yes", but I want to make sure the standard allows such usage.
No, if doesn't cause undefined behavior.
The standard defines empty iterator range in 24.1/7 and nowhere it says that supplying an empty range to std::fill algorithm causes undefined behavior.
This is actually what one would expect from a well-thought through implementation. With algorithms that handle emtpy range naturally, imposing the requirement to check for empty range on the caller would be a serious design error.
Although I don't believe it's specifically forbidden in the standard, I would say no. The standard requires that iterator ranges be of type [first, last) which includes first and everything up to but not including last. Passing in the same value for first and last doesn't make logical sense with this definition as it would be both included and not included, so I would expect to get undefined behavior back.
EDIT:
Cleaned up my initial response, and adding this: after brushing up on my mathematical interval notation, I've discovered that an interval of the form [x,x) is defined as the empty set. So my above answer is wrong -- I would NOT expect to get undefined behavior.