what's wrong with vector::reserve? [duplicate] - c++

This question already has answers here:
Choice between vector::resize() and vector::reserve()
(4 answers)
Why can't you access memory allocated by vector::reserve
(3 answers)
Closed 3 years ago.
I am just trying to learn STL for Competitive programming and stuck with this doubt!
1. When i use vector::reserve(n) my loops labeled as loop1 and loop2 don't print anything.
2. but when i use vector::assign(n,0) my loops labeled as loop 1 and loop 2 works fine.
why is it so?
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
int test;
scanf("%d", &test);
while (test > 0) {
int n;
scanf("%d", &n);
vector<int> arr;
arr.reserve(n);
//arr.assign(n,0);
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
sort(arr.begin(), arr.end());
vector<int>::iterator itr;
// loop1
for (int x : arr) {
printf("%d ", x);
}
//loop2
for (itr = arr.begin(); itr != arr.end(); itr++) {
printf("%d ", *itr);
}
test--;
}
return 0;
}

This is a common mistake. std::vector::reserve does not create elements or change the size of the container; you're actually causing undefined behavior. reserve changes just the capacity. You are looking for std::vector::resize to change the size. Here's an example for clarity:
#include <iostream>
#include <vector>
int main() {
std::vector<int> ivec;
std::cout << ivec.size() << " - " << ivec.capacity() << '\n'; // 0 - 0
ivec.reserve(100);
std::cout << ivec.size() << " - " << ivec.capacity() << '\n'; // 0 - 100
ivec.resize(30);
std::cout << ivec.size() << " - " << ivec.capacity() << '\n'; // 30 - 100
}

vector::reserve doesn't change the size of the vector. Instead, it just allocates additional memory, increasing the capacity of the vector for operations such as push_back.
For example:
std::vector<int> v;
// v.size() == 0, v.capacity() == 0
for(int i = 0; i < 100; i++) {
v.push_back(i); // This will resize the vector a few times
}
// v.size() == 100, v.capacity() >= 100
Versus
std::vector<int> v;
v.reserve(100);
// v.size() == 0, BUT v.capacity() >= 100
for(int i = 0; i < 100; i++) {
v.push_back(i); // This won't resize the vector now
}
If you want to change the size of the vector, use vector::resize.

Related

Why erasing element from vector while iterating causes Segmentation fault (core dumped)?

The following generates the problem I am having in a larger scale program.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec{1, 2, 3, 4, 5};
for (unsigned i = vec.size() - 1; i >= 0; --i) {
if (vec[i] > 2) vec.erase(vec.begin() + i);
else cout << vec[i] << " ";
}
cout << endl;
return 0;
}
This causes Segmentation fault (core dumped).
After a bit debugging, I found that changing the code the following way, "solves" the problem.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec{1, 2, 3, 4, 5};
for (unsigned i = vec.size() - 1; i >= 1; --i) {
if (vec[i] > 2) vec.erase(vec.begin() + i);
else cout << vec[i] << " ";
}
if (vec[0] > 2) vec.erase(vec.begin());
else cout << vec[0] << " ";
cout << endl;
return 0;
}
This is printing what I expected to get.
2 1
Is not it what the for loop was doing in the first program? I just moved the condition for the beginning of the vector outside the loop!
Also what is the proper way to erase element from vector while iterating like so?
As the comment says, i is unsigned, therefore i >= 0 is always true. When i becomes less than 0 it actually becomes a large positive number, and then indexing into the vector with i invokes undefined behavior.
The proper way to erase elements from a vector is to use the erase-remove-if idiom:
vec.erase(std::remove_if(vec.begin(), vec.end(), [](int i) {
return i > 2; }), vec.end());

Do not allow additon of more elements into a vector

I need to reserve x number of elements in a std::vector, say 10. Then I need to write some y number of values into it, say 5 (most of the time y < x). Is there a way to say how many values have been written to it and how may are still available?
Example:
Say I allocate 10 elements
std::vector<int> v(10);
But I only fill 7 of these elements
for (unsigned i = 0; i<7; i++)
v[i] = i;
How can I tell that 7 elements have been filled and I still have 3 available?
I tried running
v.size() and v.capacity() but both return 10.
Do you mean something like this?
std::vector<int> a; // dont allocate anything
// allocate memory for 10 elements,
// but dont actually create them. a.size() is still 0.
a.reserve(10);
for(std::size_t i = 0; i < 7; ++i) {
// copy i to a new element at the back
// of the vector. This will never reallocate
// memory, as long as at most 10 elements
// are pushed:
a.push_back(i);
}
// a.size() is now 7
Edit: I added a method using std::unique_ptr.
If C++17 is available to you, how about replacing v's elements by std::optional<int> as follows ?
#include <iostream>
#include <optional>
#include <vector>
#include <algorithm>
int main()
{
std::vector<std::optional<int>> v(10);
for (std::size_t i = 0; i<7; ++i){
v[i] = i;
}
std::cout
<< (v.size() - std::count(v.cbegin(), v.cend(), std::nullopt))
<< " elements have been filled and I still have "
<< std::count(v.cbegin(), v.cend(), std::nullopt)
<< " available."
<< std::endl << std::endl;
for(const auto v_i : v)
{
if(v_i.has_value()){
std::cout << v_i.value() << " ";
}
}
return 0;
}
But if you are constrained by an older version, I think that std::unique_ptr would be a solution.
DEMO:
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>
int main()
{
std::vector<std::unique_ptr<int>> v(10);
for (std::size_t i = 0; i<7; ++i){
v[i] = std::make_unique<int>(i);
}
std::cout
<< (v.size() - std::count(v.cbegin(), v.cend(), nullptr))
<< " elements have been filled and I still have "
<< std::count(v.cbegin(), v.cend(), nullptr)
<< " available."
<< std::endl << std::endl;
for(const auto& v_i : v)
{
if(v_i){
std::cout << *v_i << " ";
}
}
return 0;
}
Finally, I found similar approaches here.
I need to reserve x number of elements in a std::vector, say 10.
std::vector has a reserve() method for that exact purpose.
Then I need to write some y number of values into it, say 5 (most of the time y < x). Is there a way to say how many values have been written to it and how may are still available?
The vector's capacity() is the number of elements have been allocated total, whereas its size() is the number of allocated elements that have been populated with values. So, capacity() - size() is the number of available elements that have been allocated but not assigned.
I tried running v.size() and v.capacity() but both return 10.
That is because you are calling the vector constructor that allocates AND populates elements at the same time. You are creating a vector named v that has 10 elements populated with 0. That is why size() and capacity() are both 10. None of the constructors will do what you want. You need to use the default constructor and then call reserve() separately, eg:
std::vector<int> v;
v.reserve(10); // capacity = 10
for (int i = 0; i < 7; ++i)
v.push_back(i);
size_t filled = v.size(); // size = 7
size_t available = v.capacity() - v.size(); // available = 3

Crash on vector pop_back() of only remaining entry

Code:
#include <vector>
#include <algorithm>
#include <iostream>
#include <ctime>
struct myClass {
bool bIsDead;
myClass(bool bDead) {
this->bIsDead = bDead;
}
};
void PrintVector(std::vector<myClass*> vec) {
std::cout << "The vector contains: ";
for(int i = 0; i < vec.size(); i++) {
std::cout << vec[i]->bIsDead << " ";
}
std::cout << std::endl;
}
int main() {
std::srand(std::time(0)); // use current time as seed for rng
std::vector<myClass*> myVector;
for(int i = 0; i < 10; i++) {
int tempRand = std::rand() % 2;
// int tempRand = 1;
if(tempRand == 1) {
myVector.push_back(new myClass(true));
}
else {
myVector.push_back(new myClass(false));
}
}
std::cout << "Unsorted: " << std::endl;
PrintVector(myVector);
std::sort(myVector.begin(), myVector.end(), [ ]( const myClass *lhs, const myClass *rhs )
{
return lhs->bIsDead < rhs->bIsDead;
});
std::cout << "Sorted: " << std::endl;
PrintVector(myVector);
while(myVector.back()->bIsDead) {
delete myVector.back();
myVector.pop_back();
}
std::cout << "Removed Dead Ones: " << std::endl;
PrintVector(myVector);
return 0;
}
Output for random inputs:
Unsorted:
The vector contains: 0 0 1 0 0 0 1 1 0 1
Sorted:
The vector contains: 0 0 0 0 0 0 1 1 1 1
Removed Dead Ones:
The vector contains: 0 0 0 0 0 0
Hit ENTER to continue...
Output for all 1's (i.e. pop_back removes all):
Unsorted:
The vector contains: 1 1 1 1 1 1 1 1 1 1
Sorted:
The vector contains: 1 1 1 1 1 1 1 1 1 1
Hit ENTER to continue...
For this console application I'm not given any errors or crash warnings, but it isn't outputting the two cout statements after the pop_back call for the all 1's case.
Any ideas on why popping a vector of pointers back to empty causes the program to crash?
You need to add a check for size of vector. It shouldn't be 0 if you want to access the vector's last element using back().
Change this:
while(myVector.back()->bIsDead) {
to:
while(myVector.size() > 0 && myVector.back()->bIsDead) {
Here's the correct code:
#include <vector>
#include <algorithm>
#include <iostream>
#include <ctime>
struct myClass {
bool bIsDead;
myClass(bool bDead) {
this->bIsDead = bDead;
}
};
void PrintVector(std::vector<myClass*> vec) {
std::cout << "The vector contains: ";
for(int i = 0; i < vec.size(); i++) {
std::cout << vec[i]->bIsDead << " ";
}
std::cout << std::endl;
}
int main() {
std::srand(std::time(0)); // use current time as seed for rng
std::vector<myClass*> myVector;
for(int i = 0; i < 10; i++) {
int tempRand = std::rand() % 2;
// int tempRand = 1;
if(tempRand == 1) {
myVector.push_back(new myClass(true));
}
else {
myVector.push_back(new myClass(false));
}
}
std::cout << "Unsorted: " << std::endl;
PrintVector(myVector);
std::sort(myVector.begin(), myVector.end(), [ ]( const myClass *lhs, const myClass *rhs )
{
return lhs->bIsDead < rhs->bIsDead;
});
std::cout << "Sorted: " << std::endl;
PrintVector(myVector);
while(myVector.size() > 0 && myVector.back()->bIsDead) {
delete myVector.back();
myVector.pop_back();
}
std::cout << "Removed Dead Ones: " << std::endl;
PrintVector(myVector);
return 0;
}
Quoting cppreference
Calling this function(back()) on an empty container causes undefined
behavior.
PS: You don't need to make the question look so intimidating to grab our attention.
As with most problems I have, it was something simple. Thanks to billz and juanchopanza's comments it was pointed out to me that it wasn't the pop_back() that was crashing, but rather the subsequent back() called in the while loop.
This is easily fixable in several ways, 2 examples being:
adding if(myVector.empty) {break;} into the delete's while loop
or like user3286661 said, adding a conditional to the while loop first checking if it has an element.
The problem is that you try to access myVector.back() even when the vector is already empty.
The least intrusive solution (minimal modification to your code) I can think of would this:
while (!myVector.empty() && myVector.back()->bIsDead) {
delete myVector.back();
myVector.pop_back();
}
The "right" thing to do would be to use either std::vector<myClass> or std::vector<std::unique_ptr<myClass>> (no need for manual delete) and use the erase-remove-idiom:
myVector.erase(
std::remove_if(myVector.begin(), myVector.end(),
[](const auto& p) {
return p->bIsDead; //p.bIsDead for std::vector<myClass>
}
),
myVector.end()
);
This might look more complicated, but it is safer (no accidental memory leaks), probably more efficient and makes the call to sort unnecessary.

Remove all elements from array greater than n

I'm beginner in programming. Something is giving me trouble to code. Suppose, I've an array.
int Array[] = {3,6,9,5,10,21,3,25,14,12,32,41,3,24,15,26,7,8,11,4};
I want to remove all elements which are greater than 9. How can I do this?
You can do this if you use vector. First initialize vector with your array. Then use remove_if() function. Hope this will help.
#include <algorithm>
#include <vector>
int main()
{
int Array[] = {3,6,9,5,10,21,3,25,14,12,32,41,3,24,15,26,7,8,11,4};
vector<int> V(Array, Array+20);
vector<int> :: iterator it;
it = remove_if(V.begin(), V.end(), bind2nd(greater<int>(), 9));
V.erase (it, V.end()); // This is your required vector if you wish to use vector
}
You cannot remove items from an array, since they are fixed in size.
If you used std::vector, then the solution would look like this:
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
using namespace std;
int main()
{
std::vector<int> Array = {3,6,9,5,10,21,3,25,14,12,32,41,3,24,15,26,7,8,11,4};
Array.erase(remove_if(Array.begin(), Array.end(), [](int n) { return n > 9; }),
Array.end());
copy(Array.begin(), Array.end(), ostream_iterator<int>(cout, " "));
}
Live example: http://ideone.com/UjdJ5h
If you want to stick with your array, but mark the items that are greater than 10, you can use the same algorithm std::remove_if.
#include <algorithm>
#include <iostream>
#include <iterator>
using namespace std;
int main()
{
int Array[] = {3,6,9,5,10,21,3,25,14,12,32,41,3,24,15,26,7,8,11,4};
int *overwrite_start = remove_if(std::begin(Array), std::end(Array), [](int n){ return n>9; });
fill(overwrite_start, std::end(Array), -1);
copy(std::begin(Array), std::end(Array), ostream_iterator<int>(cout, " "));
}
The above will move the "erased" items to the end of the array, and mark them with -1.
Live example: http://ideone.com/7rwaXy
Note the usage in both examples of the STL algorithm functions. The second example with the array uses the same remove_if algorithm function. The remove_if returns the start of the "erased" data, as remove_if doesn't actually remove, but moves the data to the end of the sequence.
i am try swap concept without using vector
int Array[] = {3,6,9,5,10,21,3,25,14,12,32,41,3,24,15,26,7,8,11,4};
int n;
int arr_len = sizeof(Array)/sizeof(int);
void print_array_value() {
int i;
cout << "\n";
for (i = 0; i < arr_len; i++) {
cout << Array[i] << ", ";
}
cout << " : " << arr_len << "\n";
}
void swap_array_value(int start) {
int i;
for ( ; (start+1) < arr_len; start++) {
Array[start] = Array[start+1];
}
}
void remove_array_value() {
int i;
for (i = 0; i < arr_len; i++) {
if (Array[i] > n) {
swap_array_value(i);
arr_len--;
i--;
}
}
}
void main () {
clrscr();
cout << "Enter the N value : ";
cin >> n;
print_array_value();
remove_array_value();
print_array_value();
cout << "Array Length : " << arr_len;
getch();
}

swap array values in c++

I want to shift left array values if my v=4 is in a[n],remove 4 from a[n] and at the end index add 0,how i can do this?
#include <iostream>
using namespace std;
const int n=5;
int main()
{
int a[n]={1,5,4,6,8}, v=4;
int b[n];
cout << "Enter a Value" << endl;
cout<<v<<endl;
for(int i=0; i<n; i++){
cout<<a[i];
}
cout<<endl;
for(int j=0; j<n; j++){
b[j]=a[j];
if(a[j]==v)
b[j]=a[++j];
cout<<b[j];
}
return 0;
}
#include <vector> // needed for vector
#include <algorithm> // needed for find
#include <iostream> // needed for cout, cin
using namespace std;
// Vectors are just like dynamic arrays, you can resize vectors on the fly
vector<int> a { 1,5,4,6,8 }; // Prepare required vector
int v;
cout << "enter value"; // Read from user
cin >> v;
auto itr = find( a.begin(), a.end(), v); // Search entire vector for 'v'
if( itr != a.end() ) // If value entered by user is found in vector
{
a.erase(itr); // Delete the element and shift everything after element
// Toward beginning of vector. This reduces vector size by 1
a.push_back(0); // Add 0 in the end. This increases vector size by 1
}
for( int i : a ) // Iterate through all element of a (i holds element)
cout << i; // Print i
cout << '\n'; // Line end
a few helpful links:
vector , find , iterator , erase , push_back
You could use std::rotate. I suggest that you use std::vector instead of C arrays and take full advantage of the STL algorithms. Nevertheless, below I'm illustrating two versions one with C arrays and one with std::vector:
Version with C array:
#include <iostream>
#include <algorithm>
int main()
{
int const n = 5;
int a[n] = {1,5,4,6,8};
std::cout << "Enter a Value" << std::endl;
int v;
std::cin >> v;
for(auto i : a) std::cout << i<< " ";
std::cout << std::endl;
auto it = std::find(std::begin(a), std::end(a), v);
if(it != std::end(a)) {
std::rotate(it + 1, it, std::end(a));
a[n - 1] = 0;
}
for(auto i : a) std::cout << i<< " ";
std::cout << std::endl;
return 0;
}
Version with vector:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> a{1,5,4,6,8};
std::cout << "Enter a Value" << std::endl;
int v;
std::cin >> v;
for(auto i : a) std::cout << i<< " ";
std::cout << std::endl;
auto it = std::find(std::begin(a), std::end(a), v);
if(it != std::end(a)) {
std::rotate(it + 1, it, std::end(a));
a.back() = 0;
}
for(auto i : a) std::cout << i<< " ";
std::cout << std::endl;
return 0;
}
Here's an example using std::array
#include <array>
#include <algorithm>
// defines our array.
std::array<int, 5> a = {{ 1, 2, 3, 4, 5 }};
// find the position of the element with the value 4.
auto where = std::find(a.begin(), a.end(), 4);
// if it wasn't found, give up
if (where == a.end())
return 0;
// move every element past "where" down one.
std::move(where + 1, a.end(), where);
// fill the very last element of the array with zero
a[ a.size() - 1] = 0;
// loop over our array, printing it to stdout
for (int i : a)
std::cout << i << " ";
std::cout << "\n";
Why would anyone use these awkward algorithms? Well, there are a few reasons. Firstly, they are container-independant. This will work with arrays and vectors and deques, no problem. Secondly, they can be easily used to work with a whole range of elements at once, not just single items, and can copy between containers and so on. They're also type-independant... you acn have an array of strings, or an vector of ints, or other more complex things, and the algorithms will still work just fine.
They're quite powerful, once you've got over their initial user-unfriendliness.
You can always use either std::array or std::vector or whatever without using the standard library algorithms, of course.
std::array<int, 5> a = {{ 1, 2, 3, 4, 5 }};
size_t where = 0;
int to_remove = 4;
// scan through until we find our value.
while (a[where] != to_remove && where < a.size())
where++;
// if we didn't find it, give up
if (where == a.size())
return 0;
// shuffle down the values
for (size_t i = where; i < a.size() - 1; i++)
a[i] = a[i + 1];
// set the last element to zero
a[ a.size() - 1] = 0;
As a final example, you can use memmove (as suggested by BLUEPIXY) to do the shuffling-down operation in one function call:
#include <cstring>
if (where < a.size() - 1)
memmove(&a[where], &a[where + 1], a.size() - where);