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.
Related
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.
I'm doing some stuff with vectors and I'm trying to write a program that can loop through and perform operations on objects inside a vector. I've read a lot about minimal code so I've programmed this little application to illustrate the problem.
The output of this program is:
Element 1 is equal to 2
Element 2 is equal to 4
Element 1 is equal to 2
Element 2 is equal to 4
Press any key to continue...
The output should be:
Element 1 is equal to 2
Element 2 is equal to 4
Element 1 is equal to 7
Element 2 is equal to 9
Press any key to continue...
Why am I not achieving the desired output?
#include <vector>
#include <iostream>
// Some object
class A {
public:
A(int data)
: data(data)
{}
int data;
};
class B {
public:
// A function that adds a new 'A' object to the vector in class b
void push_back_to_vector(A &element);
// A function that changes the data of the objects stored in vector_of_a
void add_to_vector();
// A vector to hold objects of A
std::vector<A> vector_of_a;
};
void B::push_back_to_vector(A &element) {
vector_of_a.push_back(element);
}
void B::add_to_vector() {
for (size_t i = 0; i < vector_of_a.size(); i++) {
// Add five to all the elements in the vector
vector_of_a[i].data += 5;
}
}
int main() {
A element_1(2);
A element_2(4);
B b;
b.push_back_to_vector(element_1);
b.push_back_to_vector(element_2);
std::cout << "Element 1 is equal to " << element_1.data << std::endl;
std::cout << "Element 2 is equal to " << element_2.data << std::endl;
// This should change element_1.data to 7 and element_2.data to 9
b.add_to_vector();
std::cout << "Element 1 is equal to " << element_1.data << std::endl;
std::cout << "Element 2 is equal to " << element_2.data << std::endl;
system("pause");
return 0;
}
The push_back copies new elements. If you want to do what you seem to want to do, you need to store pointers to A, not just A.
Basically, your code is just this:
A element_1(2);
A element_2(4);
std::cout << "Element 1 is equal to " << element_1.data << std::endl;
std::cout << "Element 2 is equal to " << element_2.data << std::endl;
std::cout << "Element 1 is equal to " << element_1.data << std::endl;
std::cout << "Element 2 is equal to " << element_2.data << std::endl;
system("pause");
return 0;
Everything related to B doesn't work. Try this:
class B {
public:
// A function that adds a new 'A' object to the vector in class b
void push_back_to_vector(A *element);
// A function that changes the data of the objects stored in vector_of_a
void add_to_vector();
// A vector to hold objects of A
std::vector<*A> vector_of_a;
};
void B::push_back_to_vector(A* element) {
vector_of_a.push_back(element);
}
void B::add_to_vector() {
for (size_t i = 0; i < vector_of_a.size(); i++) {
// Add five to all the elements in the vector
vector_of_a[i]->data += 5;
}
}
And pass pointers:
b.push_back_to_vector(&element_1);
b.push_back_to_vector(&element_2);
Of course, be aware of the lifetime of the objects on the stack that you are pointing to in B.
I've noticed some behaviour which I can't understand in parameterized constructors. Given the following program:
#include <iostream>
using namespace std;
class A {
public:
int x;
A() {}
A(int i) : x(i){
cout << "A\n";
}
~A(){
cout << "dA\n";
}
};
int main(){
A p;
p = 3;
cout << p.x << endl;
p = 5;
cout << p.x << endl;
return 0;
}
I get as output:
A
dA
3
A
dA
5
dA
This means that using = triggers the parameterized constructor, destroys the object on which it's called and creates a new object.
I cannot understand this behaviour and I can't find the answer in the standard ( I am sure it is there somewhere, but it may be stated in a sophisticated way). Could someone help me with an explanation?
The phrase you're probably looking for is "implicit conversion".
If you add a copy constructor and an assignment operator, and then give each object a unique ID, it's easier to see where things go:
int counter = 0;
class A {
public:
int id;
A(): id(++counter) {cout << "A(): " << id << "\n";}
A(int i) : id(++counter) {cout << "A(" << i << "): " << id << "\n";}
// Don't copy the id.
// (This isn't used anywhere, but you can't see that it's not used unless it exists.)
A(const A& a) : id(++counter) {cout << "A(" << a.id << "): " << id << "\n";}
// Don't copy the id here either.
A& operator=(const A&a) {cout << id << " = " << a.id << "\n"; return *this;}
~A(){cout << "destroy: " << id << "\n";}
};
int main(){
A p;
cout << "p is " << p.id << "\n";
p = 3;
cout << "p is " << p.id << "\n";
p = 5;
cout << p.id << "\n";
}
Output:
A(): 1
p is 1
A(3): 2
1 = 2
destroy: 2
p is 1
A(5): 3
1 = 3
destroy: 3
1
destroy: 1
As you can see, the parameterized constructor is used to create a temporary object whose value can be assigned to p, and that temporary is destroyed immediately after that.
You can also see that p is alive and well until the very end.
With a statement like
p = 3;
what you're actually doing is
p = A(3);
which really translates to
p.operator=(A(3));
The temporary A object created by A(3) of course needs to be destructed, it is temporary after all.
The object p itself will not be destructed by the assignment.
I want to write a library wrapper class (LibWrap) around a C library that uses malloc/free. To do this I want to use C++'s RAII to allocate and free memory. I used lib_address as a random example address that I would receive from the library. However when defining my memeber variable the destructor that is called somehow has this lib_address.
I would expect the destructor of the member variable created by the default constructor not to know the new address that I am putting into the constructor of my replacement member variable.
#include <stdlib.h>
#include <iostream>
using namespace std;
class LibWrap
{
int j;
int lib_address;
public:
LibWrap(): //default LibWrap
j(0),
lib_address(0)
{
cout << "default LibWrap "<<j <<"\t\t"<<lib_address << "\t" << this<<endl;
}
LibWrap(int f_j): //special LibWrap
j(0),
lib_address(0)
{
j = f_j;
lib_address = rand();
cout << "special LibWrap " << j<<"\t"<< lib_address<< "\t" << this <<endl;
}
~LibWrap()
{
cout << "killing LibWrap " << j<<"\t" <<lib_address <<"\t" << this<< endl;
}
int g()
{
return j;
}
};
class A
{
int i;
LibWrap b;
public:
A(): //default A
i(0)
{
cout << "default A\t"<<i << endl;
}
A(int f_i)://special A
i(0)
{
i = f_i;
cout << "special A\t"<<i << endl;
b = LibWrap(10);
}
~A()
{
cout << "killing A\t"<<i << endl;
}
void p()
{
cout <<"Test values: "<< i<< "," << b.g() << endl;
}
};
int f()
{
//A a; a.p();
cout << "variable\t\tlib_address\treal_address" << endl;
A a = A(1);
cout << "End" << endl;
//a.p();
}
int main()
{
f();
}
Running this code I would expect to get the following result:
variable lib_address real_address
default LibWrap 0 0 0xbfef2e28
special A 1
special LibWrap 10 1804289383 0xbfef2df8
killing LibWrap 10 1804289383 0xbfef2df8 --would expect kiling LibWrap 0 0 0xbfef2e28
End
killing A 1
killing LibWrap 10 1804289383 0xbfef2e28 --would expect killing LibWrap 10 1804289383 0xbfef2df8
b = LibWrap(10);
This does not initialize b. b has already been initialized as part of constructing A. What you're doing is creating a temporary LibWrap and copying that temporary into b. Then, you're destroying that temporary LibWrap (which is where the extra destructor call with the lib_address comes from).
The temporary LibWrap is where the "0xbfef2df8" address comes from. The b variable is the "0xbfef2e28" address. That's why you're getting them in that order.
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.