vector::clear in C++ - c++

I have some difficulties in understanding the behaviour of the C++ clear function, when applied to a vector.
I tried to compile and run the following function:
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
unsigned int i;
vector<int> myvector;
myvector.push_back (1);
myvector.push_back (2);
myvector.push_back (3);
cout << "myvector contains:";
for (i=0; i<myvector.size(); i++) cout << " " << myvector[i];
myvector.clear();
myvector.push_back (11);
myvector.push_back (12);
cout << "\nmyvector contains:";
for (i=0; i<myvector.size(); i++) cout << " " << myvector[i];
cout << endl;
cout << " entry3 = " << myvector[2]<<endl;
return 0;
}
And this is the output:
myvector contains: 1 2 3
myvector contains: 11 12
entry3 = 3
How is it possible that the information of the third entry of the vector has not been erased when clearing the vector?

From the docs:
All the elements of the vector are dropped: their destructors are called, and then they are removed from the vector container, leaving the container with a size of 0.
Basically you're invoking undefined behavior on myvector[2] because that item no longer exists. You only pushed 2 elements in the vector after calling clear(), so only indices 0 and 1 are accessible.
You're unlucky that it didn't crash, because appearing to work can hide bugs. There's no guarantee that the value is erased.
Trying to access the element with .at(2) instead will result in an exception being thrown (operator[]() doesn't do any bound-checking, whereas at() does).

If you attempt to run this code in debug mode, it's likely it will crash with a debug assertion. Referencing past the end of an array is undefined behaviour.
What's actually happening is that vector has not wiped the memory it was previously using before you ran clear(). This memory is still present but it's not defined what will happen if you access it. It's up to you to perform bounds checking to avoid running off the end of a vector. You can do this by looping with size() as a bounds, or by using at() and catching the out_of_range exception. I wouldn't particularly recommend this latter approach since it's not a good idea to use exceptions for runtime checks.

Related

Visual Studio does not show in which line error is

When I am programming in C++ and Visual Studio 2019 throws an error, it shows in which line it was encountered. But when coding with C++ when error is thrown, it does not show in which line exactly it appears. So it makes hard to debug and fix my program. Maybe there are settings that I need to adjust?
C++ error (it point to some 1501 line of installation files that weren't created by me):
vector<int> myVector(2);
cout << myVector[4] << endl;
Errors in both programs in these examples are of a same category: vector (in C++).
Without providing more code and looking at the minimal c++ code you provided:
vector<int> myVector(2);
cout << myVector[4] << endl;
It looks like you have too many elements in myVector in the second line. You will have UB because the [] operator does not allocated more elements. You only declared 2 elements.
Now, when you send your vector to cout you are saying you have 4 which is false.
That is why you are getting the error: "Expression: vector subscript out of range".
You only have two indices 0 and 1, if you define a vector with 2 elements.
Now if you were trying to see the size of your vector you use the .size() function which returns the number of elements in the vector.
vector<int> myVector(2);
cout << myVector.size() << endl;
You could even do something like this with a for loop:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> myVector(2);
std::cout << myVector.size() << std::endl;
for (int i = 0; i < 10; i++)
myVector.push_back(i);
std::cout << myVector.size() << '\n';
return 0;
}

C++11 vector argument to thread appears uninitialized

I am trying to create a proof of concept for inter-thread communication by meanings of shared state: the main thread creates worker threads giving each a separate vector by reference, lets each do its work and fill its vector with results, and finally collects the results.
However, weird things are happening for which I can't find an explanation other than some race between the initialization of the vectors and the launch of the worker threads. Here is the code.
#include <iostream>
#include <vector>
#include <thread>
class Case {
public:
int val;
Case(int i):val(i) {}
};
void
run_thread (std::vector<Case*> &case_list, int idx)
{
std::cout << "size in thread " << idx <<": " << case_list.size() << '\n';
for (int i=0; i<10; i++) {
case_list.push_back(new Case(i));
}
}
int
main(int argc, char **argv)
{
int nthrd = 3;
std::vector<std::thread> threads;
std::vector<std::vector<Case*>> case_lists;
for (int i=0; i<nthrd; i++) {
case_lists.push_back(std::vector<Case*>());
std::cout << "size of " << i << " in main:" << case_lists[i].size() << '\n';
threads.push_back( std::thread( run_thread, std::ref(case_lists[i]), i) );
}
std::cout << "All threads lauched.\n";
for (int i=0; i<nthrd; i++) {
threads[i].join();
for (const auto cp:case_lists[i]) {
std::cout << cp->val << '\n';
}
}
return 0;
}
Tested on repl.it (gcc 4.6.3), the program gives the following result:
size of 0 in main:0
size of 1 in main:0
size of 2 in main:0
All threads lauched.
size in thread 0: 18446744073705569740
size in thread 2: 0
size in thread 1: 0
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
exit status -1
On my computer, besides something like the above, I also get:
Segmentation fault (core dumped)
It appears thread 0 is getting a vector that hasn't been initialized, although the vector appears properly initialized in main.
To isolate the problem, I have tried going single threaded by changing the line:
threads.push_back( std::thread( run_thread, std::ref(case_lists[i]), i) );
to
run_thread(case_lists[i], i);
and commenting out:
threads[i].join();
Now the program runs as expected, with the "threads" running one after another before the main collects the results.
My question is: what is wrong with the multi-threaded version above?
References (and iterators) for a vector are invalidated any time the capacity of the vector changes. The exact rules for overallocation vary by implementation, but odds are, you've got at least one capacity change between the first push_back and the last, and all the references made before that final capacity increase are garbage the moment it occurs, invoking undefined behavior.
Either reserve your total vector size up front (so push_backs don't cause capacity increases), initialize the whole vector to the final size up front (so no resizes occur at all), or have one loop populate completely, then launch the threads (so all resizes occur before you extract any references). The simplest fix here would be to initialize it to the final size, changing:
std::vector<std::vector<Case*>> case_lists;
for (int i=0; i<nthrd; i++) {
case_lists.push_back(std::vector<Case*>());
std::cout << "size of " << i << " in main:" << case_lists[i].size() << '\n';
threads.push_back( std::thread( run_thread, std::ref(case_lists[i]), i) );
}
to:
std::vector<std::vector<Case*>> case_lists(nthrd); // Default initialize nthrd elements up front
for (int i=0; i<nthrd; i++) {
// No push_back needed
std::cout << "size of " << i << " in main:" << case_lists[i].size() << '\n';
threads.push_back( std::thread( run_thread, std::ref(case_lists[i]), i) );
}
You might be thinking that vectors would overallocate fairly aggressively, but at least on many popular compilers, this is not the case; both gcc and clang follow a strict doubling pattern, so the first three insertions reallocate every time (capacity goes from 1, to 2, to 4); the reference to the first element is invalidated by the insertion of the second, and the reference to the second is invalidated by the insertion of the third.

std vector does not throw out_of_range exception when accessing uninitialized elements [duplicate]

This question already has answers here:
Vector going out of bounds without giving error
(4 answers)
Closed 5 years ago.
I read this tutorial
std::vector beginners tutorial
and also saw this question:
similar tpoic question
Yet, when I run my simple example I did not see the excepted results, which are --> an std::out_of_range exception is NOT thrown.
Did I misunderstand here something ?
The sample code I run is the following (the code run and terminates successfully, i.e.- no exceptions thrown):
#include <iostream>
#include <vector>
using namespace std;
class MyObjNoDefualtCtor
{
public:
MyObjNoDefualtCtor(int a) : m_a(a)
{
cout << "MyObjNoDefualtCtor::MyObjNoDefualtCtor - setting m_a to:" << m_a << endl;
}
MyObjNoDefualtCtor(const MyObjNoDefualtCtor& other) : m_a(other.m_a)
{
cout << "MyObjNoDefualtCtor::copy_ctor - setting m_a to:" << m_a << endl;
}
~MyObjNoDefualtCtor()
{
cout << "MyObjNoDefualtCtor::~MyObjNoDefualtCtor - address is" << this << endl;
}
// just to be sure - explicitly disable the defualt ctor
MyObjNoDefualtCtor() = delete;
int m_a;
};
int main(int argc, char** argv)
{
// create a vector and reserve 10 int's for it
// NOTE: no insertion (of any type) has been made into the vector.
vector<int> vec1;
vec1.reserve(10);
// try to access the first element - due to the fact that I did not inserted NOT even a single
// element to the vector, I would except here an exception to be thrown.
size_t index = 0;
cout << "vec1[" << index << "]:" << vec1[index] << endl;
// now try to access the last element - here as well: due to the fact that I did not inserted NOT even a single
// element to the vector, I would excpet here an excpetion to be thrown.
index = 9;
cout << "vec1[" << index << "]:" << vec1[index] << endl;
// same thing goes for user defined type (MyObjNoDefualtCtor) as well
vector<MyObjNoDefualtCtor> vec2;
vec2.reserve(10);
// try to access the first element - due to the fact that I did not inserted NOT even a single
// element to the vector, I would except here an exception to be thrown.
index = 0;
cout << "vec2[" << index << "]:" << vec2[index].m_a << endl;
// now try to access the last element - here as well: due to the fact that I did not inserted NOT even a single
// element to the vector, I would except here an exception to be thrown.
index = 9;
cout << "vec2[" << index << "]:" << vec2[index].m_a << endl;
return 0;
}
Notes:
The sample code is compiled with -std=c++11 option.
Compiler version is g++ 5.4 (on my Ubuntu 16.04 machine).
Thanks,
Guy.
A vectors operator[] function may or may not do bounds-checking. The implementations that do have bounds-checking, typically only does it for debug-builds. GCC and its standard library doesn't.
The at function on the other hand, does have mandatory bounds-checking and will be guaranteed to throw an out_of_range exception.
What happens here is simply that you go out of bounds and have undefined behavior.
Is at() that perform the range check, not (necessarily) operator[].
Your code have udefinded behaviour.
If you want to be sure to get an exception, use
vec1.at(index)
instead of
vec1[index]

Getting out-of-range error when trying to create and populate a vector using a for loop (C++)

I'm trying to create a vector where each element is a multiple of 3 below 1000. I tried two ways, only one of which worked. The non-functioning way was:
int main() {
vector<int> multiples_of_three;
for (int i = 0; i <= 1000/3; ++i)
multiples_of_three[i] = 3*i;
cout << multiples_of_three[i] << "\n";
}
That gave an out of range error specifically on multiples_of_three[i]. This next bit of code worked:
int main() {
vector<int> multiples_of_three(334);
for (int i = 0; i < multiples_of_three.size(); ++i) {
multiples_of_three[i] = 3*i;
cout << multiples_of_three[i];
}
So if I defined the size of the vector I could keep it within it's constraints. Why is it that if I try and let the for loop dictate the number of elements I get an out of range error?
Thanks!
This works perfectly fine:
#include <iostream>
#include <vector>
using namespace std;
//this one is the edited version
int main() {
vector<int> multiples_of_three(334); //notice the change: I declared the size
for (int i = 0; i <= 1000 / 3; ++i){
multiples_of_three[i] = 3 * i;
cout << multiples_of_three[i] << "\n";
}
system("pause");
}
Consider these two examples below:
//=========================the following example has errors =====================
int main() {
vector<int> multiples_of_three;
multiples_of_three[0] = 0; // error
multiples_of_three[1] = 3; // error
cout << "Here they are: " << multiples_of_three[0]; cout << endl;
cout << "Here they are: " << multiples_of_three[1]; cout << endl;
cout << endl;
system("pause");
return 0;
}
//============================the following example works==========================
int main() {
vector<int> multiples_of_three;
multiples_of_three.push_back(0);
multiples_of_three.push_back(3);
cout << "Here they are: " << multiples_of_three[0]; cout << endl;
cout << "Here they are: " << multiples_of_three[1]; cout << endl;
cout << endl;
system("pause");
return 0;
}
So unless, you have declared the size, never use indices directly for assigning values (as in the first example). However, if the values have already been assigned, you can use indices to retrieve the values (as in the 2nd example). And in case, You want to use indices to assign values, first declare the size of the array (as in the edited version)!
the default constructor (that is called here: vector<int> multiples_of_three;) creates an empty vector. you can populate them with push_back or better if you know the number of objects you have to add, pass that number to the constructor, so it reserves the required amount of memory at once instead of constantly growing (that means allocating memory and copying the old menory into the new) the vector.
another alternative is to call reserve from the empty default contructed vector and use push_back to populate it. reserve reserves enough memory to keep the required amount of objects but without changing the size of the vector. advantage of reserve is that the default constructor is not called for every object (as it will be done with resize or parameterized constructor) that would be not necessary since you overwrite the the object in your initialization loop right after the creation of the vector.
You need to use push_back() rather than add via the indexer.
The indexer can be used for read/write access to a vector only within the bounds.
A vector doesn't magically grow in size because you use []. It started out with 0 elements in the first example and you never grew it.

List iterator vs. vector iterator

I have two questions regarding iterators.
I thought the once you define an iterator to an STL container such as a vector or a list, if you add elements to the containers then these iterators won't be able to access them. But the following code defines a list of five elements and then adds another element in each loop iteration and results in an infinite loop:
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> ls;
for(int i = 0; i < 5; i++)
{
ls.push_back(i);
}
int idx = 0;
for(list<int>::iterator iter = ls.begin(); iter != ls.end(); iter++)
{
cout << "idx: " << idx << ", *iter: " << *iter << endl;
ls.push_back(7);
idx++;
}
}
However, doing the same for a vector results in an error:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec;
for(int i = 0; i < 5; i++)
{
vec.push_back(i);
}
int idx = 0;
for(vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++)
{
cout << "idx: " << idx << ", *iter: " << *iter << endl;
vec.push_back(7);
idx++;
}
}
I thought that when the vector container must be resized, it does so at powers of 2 and is located to a new area of memory, which is why you shouldn't define an iterator to a vector if you adding elements to it (since the iterators don't get passed to the new memory location). For example, I thought a vector containing 16 elements, after calling the push_back function, will be allocated space for 32 elements and the entire vector will be relocated. However, the this didn't happen for the following code. Was I just mistaken?
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec;
for(int i = 0; i < 4; i++)
{
vec.push_back(i);
cout << "address of vec: " << &vec << ", capacity: " << vec.capacity() << endl;
}
for(int i = 0; i < 20; i++)
{
vec.push_back(i);
cout << "address of vec: " << &vec << ", capacity: " << vec.capacity() << endl;
}
}
Different container's iterators have different properties. Here are the iterator invalidation rules.
The list loop: When you push onto a list all previous iterators still valid. You will never hit the end if every time you iterator forward one you also add a new element, obviously.
The vector loop: For a vector, your iterators are invalid once a push_back results in the new size exceeding the old capacity. As soon as this happens, using iter is undefined behavior (you will likely crash).
I thought that when the vector container must be resized, it does so
at powers of 2 and is located to a new area of memory
This is unspecified by the standard. Some implementations of the C++ standard library double the capacity of a vector when the size exceeds the old capacity, and others grow at different rates.
The answer on your first question is contained in the second your question.
As for the second question then it is implementation defined how the vector allocates the memory. It is not necessary that it will double the size of the memory each time when it is exhausted.
The different containers generally have different guarantees with respect to the validity of iterators, and pointers/references to elements:
For std::list<T> the iterators and pointers/references to elements stay valid until the corresponding node gets erased or the std::list<T> exists.
For std::vector<T> the validity is more complicated:
Iterator and pointer/reference validity is identical (and I'll only use iterators below).
All iterators are invalidated when the std::vector<T> needs to resize its internal buffer, i.e., when inserting exceeds the capacity. When the capacity is exceeded and how much memory is allocated depends on the implementation (the only requirement is that the capacity grows exponentially and a factor of 2 is a reasonable choice but there are many others).
When inserting into a std::vector<T> all iterators before the insertion point stay valid unless reallocation is necessary.
When erasing from a std::vector<T> all iterators past the erase point are invalidated.
Other containers have, yet, different validity constraints (e.g. std::deque<T> keeps invalidating iterators but can keep pointers/references valid).