I have a vector with some objects.
I noticed that when I remove one element from vector with erase method, I get the destructor call to the wrong element (always to the last element).
Here a minimal example that produce a bad output.
// Example program
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Test {
public:
Test(string value) {
_value = value;
cout << "Constructor:" << _value << endl;
}
Test(const Test &t) {
_value = t._value;
cout << "Copied:" << _value << endl;
}
~Test() {
cout << "Destructor:" << _value << endl;
}
string print() {
return _value;
}
string _value;
};
int main()
{
vector<Test> vec;
vec.reserve(3);
cout << "Creation" << endl << endl;
vec.push_back(Test("1"));
vec.push_back(Test("2"));
vec.push_back(Test("3"));
cout << endl << "Deleting" << endl << endl;
vec.erase(vec.begin()); // Here is called the element with value "3"
vec.erase(vec.begin()); // Here is called the element with value "3"
cout << endl << "Log" << endl << endl;
// But the final log print "3"
for (unsigned i = 0; i < vec.size(); i++) {
cout << vec[i].print()<<endl;
}
return 0;
}
The output is:
Creation
Constructor:1
Copied:1
Destructor:1
Constructor:2
Copied:2
Destructor:2
Constructor:3
Copied:3
Destructor:3
Deleting
Destructor:3 <-- WRONG, NEED TO BE 1
Destructor:3 <-- WRONG, NEED TO BE 2
Log
3
Destructor:3
I would solve this problem without change the container vector.
vec.erase(vec.begin()); does not destruct the first element. It overwrites it by shifting all of the subsequent ones by one place, using either the move- or copy-assignment operator. What remains of the last element after it has been moved from is then destructed, which is what you're observing.
Related
I have been trying to understand how the clear() function in std::vector works, I am trying to emulate the workings of a std::vector.
So far, I have learned that clear() destroys all the objects but retains the capacity of the vector.
The bit I don't understand is how does the destructor of the objects in vector are called.
class A {
public:
A(int a) {
m_a = a;
cout << "Constructed object number: " << a << endl;
}
~A() {
cout << "Destructed object number: " << m_a << endl;
}
int m_a;
};
int main() {
char** memory = new char*[100];
A t1(1);
memory[sizeof(A)*10] = reinterpret_cast<char *>(&t1);
A* t = reinterpret_cast<A*>(memory[sizeof(A)*10]);
cout << t->m_a << endl;
//Trying to figure out on how to clear the vector.
memory[sizeof(A)*10] = NULL;
//Testing on how the destructor is getting called
vector<A*> vec;
vec.push_back(&A(2)); // I know it is wrong, just here for understanding purposes.
A t2(3);
vec.push_back(&t2);
cout << "Clear" << endl;
vec.clear();
cout << "End" << endl;
return 0;
}
Clearing the vector is not calling the destructor of "t2", as it is a pointer here, but if I store objects, than destructor of "t2" is getting called in clear function.
This is only for understanding purposes as to how the std::vector actually works.
#Anurag one very important thing regarding STL container: it's keep the copy of the object/pointer/primitive type irrespective of the container type(sequence containers, associative containers and unordered container).
Now come back to your doubt 1. with object and 2. With pointer , below I am explaining with example :
Example Of Object type (See the output, you will be clear):
#include <iostream>
#include<vector>
using namespace std;
class Achintya {
static int counter ;
static int i ;
public:
Achintya() {
cout<<"Achintya Constructor called : " << ++i <<endl;
}
~Achintya() {
cout<<"Achintya destructor called : " << ++counter <<endl;
}
Achintya(const Achintya&) {
cout<<"Achintya copy constructor called : "<<endl;
}
};
int Achintya:: i;
int Achintya:: counter;
int main() {
vector<Achintya> VecAchintya;
Achintya a1;
// Address of the pointer
cout << " 1st object address : " <<&a1 <<endl;
//Push back to vector
// it is just a copy and store in vector (copy constructor is begin invoke )
VecAchintya.push_back(a1);
cout << " =============================================" << endl;
cout<< " Number of element present in vector is : " << VecAchintya.size() << endl;
cout << " =============================================" << endl;
// cli is not iterator
for(auto& cli:VecAchintya ) {
cout << " Adress of 1st element is : " << &cli <<endl;
}
// it clear the object it self which is being created at the time of the push_back()
VecAchintya.clear();
cout << " =============================================" << endl;
cout<< " Number of element present in vector is : " << VecAchintya.size() << endl;
cout << " =============================================" << endl;
}
output ::
Achintya Constructor called : 1
1st object address : 0x7ffd70ad339f
Achintya copy constructor called :
=============================================
Number of element present in vector is : 1
=============================================
Adress of 1st element is : 0x23c6c30
Achintya destructor called : 1
=============================================
Number of element present in vector is : 0
=============================================
Achintya destructor called : 2
Example Of pointer type (See the output, you will be clear):
#include <iostream>
#include<vector>
using namespace std;
class Achintya {
static int counter ;
static int i ;
public:
Achintya() {
cout<<"Achintya Constructor called : " << ++i <<endl;
}
~Achintya() {
cout<<"Achintya destructor called : " << ++counter <<endl;
}
Achintya(const Achintya&) {
cout<<"Achintya copy constructor called : "<<endl;
}
};
int Achintya:: i;
int Achintya:: counter;
int main() {
vector<Achintya *> VecAchintya;
Achintya* a1 = new Achintya();
// Address of the pointer
cout << " 1st object address : " << a1 <<endl;
//Push back to vector
// it is just a copy the pointer value and store
VecAchintya.push_back(a1);
cout << " =============================================" << endl;
cout<< " Number of element present in vector is : " << VecAchintya.size() << endl;
cout << " =============================================" << endl;
// cli is not iterator
for(auto& cli:VecAchintya ) {
cout << " Adress of 1st element is : " << cli <<endl;
}
// it clear the pointer it self which is being stored at the time push_back()
VecAchintya.clear();
cout << " =============================================" << endl;
cout<< " Number of element present in vector is : " << VecAchintya.size() << endl;
cout << " =============================================" << endl;
// call destructor explicitly
delete a1;
}
Output ::
Achintya Constructor called : 1
1st object address : 0x2533c20
=============================================
Number of element present in vector is : 1
=============================================
Adress of 1st element is : 0x2533c20
=============================================
Number of element present in vector is : 0
=============================================
Achintya destructor called : 1
You may find it easier to study pop_back and think of resize down and clear as special multi-pop calls. You could certainly implement them that way in your own implementation.
I'm trying to return a vector from a function. My code compiles and I've checked my function and reckon that the error comes from the return part. It compiles fine (using Cygwin) but when running it, I get an Aborted (core dumped) error.
Here is my code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
//function that returns the square
int f(int n)
{
return n*n;
}
vector<int> myVec;
int counter = 0;
//function that uses f on all elements in a list
vector<int> map(vector<int> something)
{
//base case
if(counter == something.size())
{
/*cout << "hello" << endl;
for (int i=0; i<counter; i++)
{
cout << "vector: " << myVec[i] << endl;
}*/
counter=0;
return myVec;
}
//recursion
else
{
//cout << "counter: " << counter << endl;
int n = f(something[counter]);
//cout << "n: " << n << endl;
myVec.push_back(n);
//cout << "vector: " << myVec[counter] << endl;
counter++;
map(something);
}
}
int main()
{
//making vectors
vector<int> L;
vector<int> L1;
vector<int> L2;
for (int i=0; i<20; i++)
{
L.push_back(i);
}
L1 = map(L);
}
The code was originally from a class file.
In your recursion, you do not return anything. The function is expected to return a Vector.
In your case, what happens if the function enters the "else" case on its first call? It reenters map() until the condition is met, then returns a vector. That vector is passed to the previous recursive call and immediately deleted, as it is not passed any further.
The solution here would be to change the last line of the else-case to
return map(something);
so the value is not lost and correctly passed through to the original caller (your main function).
ALWAYS return a vector when your return type is a vector. In your function, there's a branch that won't return anything, and that will cause problems.
vector<int> map(vector<int>& something)
{
//base case
if(counter == something.size())
{
/*cout << "hello" << endl;
for (int i=0; i<counter; i++)
{
cout << "vector: " << myVec[i] << endl;
}*/
counter=0;
return myVec;
}
//recursion
else
{
//cout << "counter: " << counter << endl;
int n = f(something[counter]);
//cout << "n: " << n << endl;
myVec.push_back(n);
//cout << "vector: " << myVec[counter] << endl;
counter++;
map(something); //you should return a vector here
return std::vector<int>(); //empty vector
}
}
Also notice the "&" symbol I added at the function call so that the vector is passed by reference. Otherwise you're passing a copy that won't be changed. I don't know what that "map" function does, so I can't suggest better models to what you're doing.
Why does item.someVector.push_back(1); seem to work, but not item.getSomeVector().push_back(1); ?
Here is my test case:
#include <iostream>
#include <vector>
using namespace std;
class Item {
public:
vector<int> someVector = vector<int>();
vector<int> getSomeVector()
{
return someVector;
}
};
int main()
{
Item item = Item();
item.getSomeVector().push_back(1);
cout << item.getSomeVector().size() << endl;
cout << item.someVector.size() << endl;
item.someVector.push_back(1);
cout << item.getSomeVector().size() << endl;
cout << item.someVector.size() << endl;
}
// output:
// 0
// 0
// 1
// 1
Because getSomeVector returns a copy of someVector. So you're updating a temporary object which is then immediately destroyed. Try changing it to vector<int>& getSomeVector()
I have this vector class, and I was provided with a driver to test the class. Most of it seems to work fine but I think there is something wrong with the exceptions part (which I haven't quite fully understood)
Here is the code for the class .cpp file
int myVector::at(int i)
{
if(i<vsize)
return array[i];
throw 10;
}
and here is the driver code
#include "myVector.h"
#include <iostream>
using namespace std;
int main()
{
// Create a default vector (cap = 2)
myVector sam;
// push some data into sam
cout << "\nPushing three values into sam";
sam.push_back(21);
sam.push_back(31);
sam.push_back(41);
cout << "\nThe values in sam are: ";
// test for out of bounds condition here
for (int i = 0; i < sam.size( ) + 1; i++)
{
try
{
cout << sam.at(i) << " ";
}
catch(int badIndex)
{
cout << "\nOut of bounds at index " << badIndex << endl;
}
}
cout << "\n--------------\n";
// clear sam and display its size and capacity
sam.clear( );
cout << "\nsam has been cleared.";
cout << "\nSam's size is now " << sam.size( );
cout << "\nSam's capacity is now " << sam.capacity( ) << endl;
cout << "---------------\n";
// Push 12 values into the vector - it should grow
cout << "\nPush 12 values into sam.";
for (int i = 0; i < 12; i++)
sam.push_back(i);
cout << "\nSam's size is now " << sam.size( );
cout << "\nSam's capcacity is now " << sam.capacity( ) << endl;
cout << "---------------\n";
cout << "\nTest to see if contents are correct...";
// display the values in the vector
for (int i = 0; i < sam.size( ); i++)
{
cout << sam.at(i) << " ";
}
cout << "\n--------------\n";
cout << "\n\nTest Complete...";
cout << endl;
system("PAUSE");
return 0;
}
Any help is appreciated. Thanks
The driver that you have provided:
try {
cout << sam.at(i) << " ";
}
catch(int badIndex) {
cout << "\nOut of bounds at index " << badIndex << endl;
}
expects that int will be thrown (a bit weird design, but well... this is the code that will use your class...). Your implementation of at() might look like this:
int& myVector::at(int i) throw(int) {
if (i < vsize)
return array[i];
throw i;
}
just try to follow one simple rule: throw by value, catch by reference.
Also note that you have a pointer:
private:
int* array;
which points to dynamically allocated memory allocated in constructor and copy constructor and freed in destructor :
myVector::myVector(int i)
{
...
array = new int[maxsize];
}
myVector::myVector(const myVector& v)//copy constructor
{
...
array =new int[maxsize];
}
myVector::~myVector()
{
delete[] array;
}
But how about the assignment operator ? See What is The Rule of Three?
Your stop condition of for loop ends it one element after the last one (i.e. you cannot access 4th element of sam vector because there are only three elements).
std::vector::at throws std::out_of_range exception in such situation (see: http://en.cppreference.com/w/cpp/container/vector/at), not int one. So you should change your exception handling part to something like this:
#include <exception>
try
{
cout << sam.at(i) << " ";
}
catch(std::out_of_range exc)
{
cout << "\nOut of bounds at index " << exc.what() << endl;
}
I'm trying to store a lambda in an object system involving several layers of indirection. I'm using g++ 4.7.1.
Depending on how exactly I construct the (equivalent) objects, the lambda may or may not have the correct value.
Code:
#include <iostream>
#include <functional> // used for std::function
using namespace std; // TODO nope
typedef function<int()> intf;
struct SaveLambda {
const intf func;
SaveLambda(const intf& _func) : func(_func) {}
};
struct StoreSaved {
const SaveLambda* child;
StoreSaved(const SaveLambda& _child) : child(&_child) {
cout << "Before returning parent: " << child->func() << endl;
}
};
int main() {
const int ten = 10;
auto S = SaveLambda([ten](){return ten;});
cout << "No indirection: " << S.func() << endl << endl;
auto saved = StoreSaved(S);
cout << "Indirection, saved: " << saved.child->func() << endl << endl;
auto temps = StoreSaved ( SaveLambda([ten](){cout << "&ten: "<< &ten << endl; return ten;}) );
cout << "***** what. *****" << endl;
cout << "Indirection, unsaved: " << temps.child->func() << endl;
cout << "***** what. *****" << endl << endl;
cout << "ten still lives: " << ten << endl;
}
Compile as g++ -std=c++11 -Wall -o itest itest.cpp and run: notice the one line of output with a different value.
What am I doing wrong? I assumed that capture-by-value would, well, capture by value. (Observe most disconcertingly that the print in StoreSaved (line 15) produces the correct value, unlike line 34, despite these both referring to the same object. The only difference is adding another layer of indirection.)
This is wrong:
auto temps = StoreSaved(
/* This temporary value dies at the last semicolon! */
SaveLambda([ten](){cout << "&ten: "<< &ten << endl; return ten;})
);
StoreSaved then has a pointer to a nonexistent object. Using it is UB.
As already pointed out by others, the problem is that in temps you end with a pointer to a nonexistent SaveLambda struct, as it is a temporary.
You can keep a copy using a SaveLambda struct in StoreSaved, instead of a pointer:
struct StoreSaved {
const SaveLambda child;
StoreSaved(const SaveLambda& _child) : child(_child) {
cout << "Before returning parent: " << child.func() << endl;
}
};
You also have to change all the child->func() to child.func(), as you are not dealing with a pointer anymore.