Moving element from container does not empty container? - c++

Given the following code:
#include <vector>
#include <iostream>
struct number {
int n{666};
};
int main()
{
std::vector<number> vec;
std::cerr << vec.size() << std::endl;
number n;
vec.push_back(n);
std::cerr << vec.size() << std::endl;
auto b = std::move(vec.front());
std::cerr << "b: " << b.n << std::endl;
std::cerr << vec.size() << std::endl;
}
I get the following output:
0
1
b: 666
1
Shouldn't the last 1 be 0?

std::move doesn't even know that the thing it moved was in a container. The block of memory that the vector owns is still there, just in an unspecified state. It's up to you to manage the vector.

Once you have used the value at the front and you want to get rid of it you will need to erase it from the vector. I won't talk about the front() returning a ref as 0x5453 mentioned that. But there is no reason to use std::move there - all that does is cast the value to a rvalue reference it does not actually "move" anything on its own.
#include <vector>
#include <iostream>
struct number {
int n{666};
};
int main()
{
std::vector<number> vec;
std::cerr << vec.size() << std::endl;
number n;
vec.push_back(n);
std::cerr << vec.size() << std::endl;
// Since this is a ref, and your struct is simple - just copy
auto b {vec.front()};
// Now remove the element
vec.erase(vec.begin());
std::cerr << "b: " << b.n << std::endl;
std::cerr << vec.size() << std::endl;
}

Related

Why is a captured variable in C++11 of different value inside a capture?

I am not sure how to explain this behaviour, displayed here with a minimal example.
Why isn't size correctly captured ?
#include <iostream>
#include <vector>
using namespace std;
auto&& matcher1KO = [] (vector<int> &v){
int size = v.size();
cout << "size outside : " << size << "\n"; // print 1
return [&] (bool b) {
cout << "v.size() : " << v.size() << "\n"; // print 1
cout << "size inside : " << size << "\n"; // print 0
};
};
auto&& matcher2OK = [] (vector<int> &v){
int size = v.size();
cout << "size outside : " << size << "\n"; // print 1
return [&] () {
cout << "v.size() : " << v.size() << "\n"; // print 1
cout << "size inside : " << size << "\n"; // print 1
};
};
int main() {
vector<int> v {+1};
auto matcherf1 = matcher1KO(v); //
matcherf1(true);
auto matcherf2 = matcher2OK(v);
matcherf2();
}
Both the code have undefined behavior, anything is possible.
The reason is the same for the two cases: the variable size is a local object inside the operator() of the lambda, it will be destroyed when the invocation ends. You're capturing size by-reference and the reference is dangled.
Changing it to capture-by-value would be fine. e.g.
return [=] (bool b) {
cout << "v.size() : " << v.size() << "\n"; // print 1
cout << "size inside : " << size << "\n"; // print 1
};

How do I only display the first 10 elements of a Vector using an Iterator?

I'm trying to use displayVectorVer2() to have it only display the first 10 elements, but I don't know how to do it with iterators. I did try a few dumb things just to see what would happen: I compared the iterator to displayLimit in my for loop. I played around by subtracting vobj.end()-5 since my professor is only having me use 15 elements, but I fully well knew this was not a good idea.
#include <iostream>
#include <vector>
#include <ctime>
template <class T>
void fillVector(std::vector<T>& vobj, int n);
template <class T>
void displayVectorVer2(std::vector<T>& vobj, typename std::vector<T>::iterator ptr);
template <class T>
void fillVector(std::vector<T>& vobj, int n)
{
srand((unsigned int)time(NULL));
for (int i=0; i<n; ++i)
{
vobj.push_back(rand()%99999+1);
}
}
template <class T>
void displayVectorVer2(std::vector<T>& vobj, typename std::vector<T>::iterator ptr)
{
std::cout << "Vector object contains " << vobj.size() << " values which are" << std::endl;
const unsigned displayLimit = 10;
if (vobj.size()>displayLimit)
{
for (ptr=vobj.begin(); ptr<vobj.end(); ++ptr)
{
std::cout << " " << *ptr;
}
std::cout << " ..." << std::endl;
}
else
{
for (ptr=vobj.begin(); ptr<vobj.end(); ++ptr)
{
std::cout << " " << *ptr;
}
std::cout << std::endl;
}
}
int main()
{
std::vector<int> vobj;
std::cout << "Before calling fillVector(...): vobj contains "
<< vobj.size() << " values." << std::endl;
std::cout << "\nEnter # of random values you'd like to store in vobj: ";
int n;
std::cin >> n;
std::cout << "\n*** Calling fillVector(...) ***" << std::endl;
fillVector(vobj, n);
std::cout << "\n*** Calling displayVectorVer2(...) ***" << std::endl;
std::vector<int>::iterator ptr;
displayVectorVer2(vobj,ptr);
}
Maybe I am thinking too simple but, that wold solve your question:
I'm trying to use displayVectorVer2() to have it only display the
first 10 elements
without knowing your full exercise, that would be my answer:
...
const unsigned displayLimit = 10;
if (vobj.size()>displayLimit)
{
for (ptr=vobj.begin(); ptr<vobj.begin()+displayLimit; ++ptr)
{
std::cout << " " << *ptr;
}
std::cout << " ..." << std::endl;
}
else
...
edit:
That worked, but why does it work? I remember adding to vobj.begin() and getting extra empty elements appended to the original vector.
Not sure what exactly you did but maybe that helps you understanding your code:
...
const unsigned displayLimit = 10;
if (vobj.size()>displayLimit)
{
//Init ptr outside the for loop
ptr = vobj.begin();
//What the for loop is seeing with a more familiar syntax:
//for( ; i < 0 +displayLimit; ++i)
//what you are seeing
for (/*ptr init*/; ptr < vobj.begin() +displayLimit; ++ptr)
{
std::cout << " " << *ptr;
}
std::cout << " ..." << std::endl;
}
...
The iterators just gives you the int value and you can use it with what ever "eats" int values. In your case the for loop.
If you tell the program to use an iterator you tell the program: "Just give me the number the Vector begins with and add 10".
In your case 0 "...and add 10"
You could also write a code like that with n passed to the function
for being able to use .end - input + 10 for showing 10 lines:
...
template <class T>
void displayVectorVer2(std::vector<T>& vobj, typename std::vector<T>::iterator ptr,int n)
{
std::cout << "Vector object contains " << vobj.size() << " values which are" << std::endl;
const unsigned displayLimit = 10;
if (vobj.size()>displayLimit)
{
ptr=vobj.begin();
for (; ptr<vobj.end() -n +displayLimit; ++ptr)
{
std::cout << " " << *ptr;
}
std::cout << " ..." << std::endl;
}
else
{
for (ptr=vobj.begin(); ptr<vobj.end(); ++ptr)
{
std::cout << " " << *ptr;
}
std::cout << std::endl;
}
}
int main()
{
std::vector<int> vobj;
std::cout << "Before calling fillVector(...): vobj contains "
<< vobj.size() << " values." << std::endl;
std::cout << "\nEnter # of random values you'd like to store in vobj: ";
int n;
std::cin >> n;
std::cout << "\n*** Calling fillVector(...) ***" << std::endl;
fillVector(vobj, n);
std::cout << "\n*** Calling displayVectorVer2(...) ***" << std::endl;
std::vector<int>::iterator ptr;
displayVectorVer2(vobj,ptr,n);
}
...
You also shouldn't use srand in modern code anymore since it is depricated for more than 10 years since c++11 introduced <random>
and srand can harm your program f.e. if used for generating seeds for sensitive code. Also srand provides not the "randomness" it should provide, srand generates some numbers more often than others - that's not random.

Elements of vector still reference-able after calling clear( )?

In the following code, I print the first element of a vector and its size, before and after calling clear( ) method of the in-built vector.
However, even after calling clear( ), I can still refer to the element of the vector( although the size is reset to '0').
Is this expected behaviour or have I not understood the behaviour of clear( ) well?
CODE:
#include <vector>
#include <iostream>
using namespace std;
int main(int argc, char *argv[]){
vector<int> vec = {1, 2, 3, 4, 5};
cout << vec[0] << " " << vec.size() << endl;
vec.clear();
for(auto i : vec)
cout << i << " ";
cout << endl;
cout << vec[0] << " " << vec.size() << endl;
return 0;
}
OUTPUT:
1 5
1 0
The indexing operator of std::vector<> does not check the index. Since it's Undefined Behavior, you might get "what was there before", or it might crash (or "whatever").
You have the at member function, which will throw if index is out of range. That is:
cout << vec.at(0) << " " << vec.size() << endl;
near the end of your main() will throw.

My range for loop doesn't work

I have to print out the size of the vector and all the contents inside it. But my for loop doesnt iterate, it doesn't go up by one but instead stays at the value 0 for the whole loop.
#include "stdafx.h"
#include <string.h>
#include <string>
#include <iostream>
#include <cctype>
#include <vector>
#include <list>
using std::string;
using std::vector;
vector<int> v2(10);
for( auto i : v2)
{
if( i == 0 )
{
std::cout << v2.size() << std::endl;
}
std::cout << "Element value " << (i) << " is " << v2[i] << std::endl;
}
So I only want to print the size once, at the start. Then print out each element value which I know will be 0 by default. But it just prints out "Element value 0 is 0" 9 times.
If you want at first to print out the size of the vector then place this output statement before the range based for statement
std::vector<int> v2(10);
std::cout << v2.size() << std::endl;
size_t i = 0;
for ( auto x : v2 )
{
std::cout << "Element value " << i++ << " is " << x << std::endl;
}
But if you are using a count then it would be better to use the ordinary for statement
std::vector<int> v2(10);
std::cout << v2.size() << std::endl;
for ( std::vector<int>::size_type i = 0; i < v2.size(); i++ )
{
std::cout << "Element value " << i << " is " << v2[i] << std::endl;
}
Your question indicates that you want to treat the first element differently. This does not work with range-based for loops out of the box. You have two options:
Use an extra variable to remember whether the first iteration was made.
Use a traditional loop, using an index variable or an iterator.
Example for 1:
bool first_iteration = true;
for( auto i : v2)
{
if (first_iteration)
{
std::cout << v2.size() << std::endl;
first_iteration = false;
}
// ...
}
Example for 2:
for (auto iter = v2.begin(); iter != v2.end(); ++iter)
{
if (iter == v2.begin())
{
std::cout << v2.size() << std::endl;
}
// ...
}

c++: Remove element from container and get it back

Is there a built-in method that removes and element (i.e. from map given a key) and returns the removed element?
There is no built-in method to do this, you can however store the element by accessing it and then erase it.
Erasing requires you to specify key.If it's a multi-map you should erase with position.
Here is a function you can use (C++11):
#include <iostream>
#include <map>
template<typename T>
typename T::mapped_type removeAndReturn(T& mp, const typename T::key_type& val) {
auto it = mp.find(val);
auto value = std::move(it->second);
mp.erase(it);
return value;
}
int main() {
std::map<int, int> m;
m[3] = 4;
std::cout << "Map is empty: " << std::boolalpha << m.empty() << std::endl;
std::cout << "Value returned: " << rm_and_return(m, 3) << std::endl;
std::cout << "Map is empty: " << std::boolalpha << m.empty() << std::endl;
}
Output:
Map is empty: false
Value returned: 4
Map is empty: true