Delete objects carried in a vector? - c++

In a C++ application I create in various points of a class User objects of a particular class Vehicle with operator new and right after each instantiation I put them in a vector which is a property of the first class (i.e. vector< Vehicle* > v1).
At the running time of the program it is likely I need to some point to delete the objects of class Vehicle. Should I use definitely the operator delete? If so, how is this be done to a vector? Is there any predefined function of the vector to do the same work? When I delete them, what happens to the properties of Vehicle class, which in this occasion are pointers to other Objects? Are they also deleted?
If it is no need to delete them until the end of the program, are they deleted by the destructor or should delete them "manually"?

Here's the C++ way:
#include <memory>
#include <vector>
#include "vehicle.hpp"
typedef std::vector<std::unique_ptr<Vehicle>> vehicle_container;
#include "derivedvehicles.hpp"
int main()
{
vehicle_container v;
//...
v.emplace_back(new Car);
v.emplace_back(new Bike);
//...
} // baam, everything is cleaned up

Here a better way (IMHO):
#include <boost/ptr_container/ptr_vector.hpp>
#include "vehicle.hpp"
typedef boost::ptr_vector<Vehicle> vehicle_container;
#include "derivedvehicles.hpp"
int main()
{
vehicle_container v;
//...
v.emplace_back(new Car);
v.emplace_back(new Bike);
//...
v[0].go(); // Elements accessed as if they are objects (not pointers)
// Which makes using in any of the standard
// algorithms trivial.
} // ta-da, everything is cleaned up

Related

Reusable std::shared_ptr

Is it possible to make std::shared_ptr not to delete an object, but move it to a list?
#include <memory>
#include <list>
struct QObject { double socialDistance; };
int main()
{
std::list<QObject *> free_objects;
std::list<QObject *> used_objects;
QObject* p_object = new QObject{10};
free_objects.push_back(p_object);
{
std::shared_ptr<QObject> p(p_object);
}
//At this point p_object is moved from free_objects to used_objects,
//so I reuse the object later.
return 0;
}
If yes, is it possible to reuse not only the objects but also the control block to avoid memory reallocation?
Is it possible to make std::shared_ptr not to delete an object, but move it to a list?
You might use custom deleter for that:
std::shared_ptr<QObject> p(p_object, [&](QObject* p){
used_objects.push_back(p);
auto it = std::find(free_objects.begin(), free_objects.end(), p);
if (it != free_objects.end()) free_objects.erase(it);
});
Demo

Using array of pointers to object in C++

I need to save objects as pointers in dynamic array but i have problem.
This is my code, there are three classes and i need to have array (arrayoftwo) of poiters to class Two that would work further with class Three and so on. I have two problems. One is that i cant figure out how to dynamically allocate space for my arrayoftwo (which i need to dynamically resize by number of stored pointers) and second problem is how to exactly store pointers to objects without destroying object itself.
Here is my code:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
class One {
public:
bool addTwo(int a);
private:
void getspace(void);
class Two {
public:
int a;
private:
class Three {
/*...*/
};
Three arrayofThree[];
};
int freeindex;
int allocated;
Two *arrayoftwo[];
};
void One::getspace(void){
// how to allocate space for array of pointers ?
arrayoftwo=new *Two[100];
allocated=100;
}
bool One::addTwo(int a){
Two temp;
temp.a=a;
getspace();
arrayoftwo[freeindex]=&temp;
freeindex++;
return true;
//after leaving this method, will the object temp still exist or pointer stored in array would be pointing on nothing ?
}
int main() {
bool status;
One x;
status = x . addTwo(100);
return 0;
}
Thank you for any help.
EDIT: I cant use vector or any other advanced containers
temp will not exist after leaving addTwo; the pointer you store to it is invalid at that point. Instead of storing the object as a local variable, allocate it on the heap with new:
Two* temp = new Two();
To allocate an array of pointers:
Two** arrayoftwo; // declare it like this
// ...
arrayoftwo = new Two*[100];
And getspace should either be passed a (from addTwo) or a should be stored as the member variable allocated and getspace should access it from there. Otherwise it's assuming 100.

vector::erase() also erases member-vectors of a struct

People, I am new to all this programming talk. Up until now it was quite easy to find answers by googling them but right here I have big trouble expressing what I want to ask, let me try: Erasing a vector calls the destructor before freeing the memory, right? Now how does a struct-vector react, if it is destructed? One does not define a destructor for these things, but is it correct to assume that if a struct is "destructed" each of its members' destructors will be called as well?
Let me give you an example:
#include <string>
#include <vector>
struct ding_t {
std::string dang;
} foo;
strung boom_t {
vector <ding_t> chuck;
} bar;
int main () {
vector <boom_t> tom;
tom.resize(10);
tom[4].chuck.resize(5);
tom[4].chuck[3].dang = "jerry";
tom.erase();
return 0;
}
in this case, will the memory allocated by
tom[4].chuck.resize(5);
be freed as well? Sorry for my vocabulary, but at this moment I am trying to move from pointers to the more sophisticated cpp language equivalent of vectors. I hope I got my point across. Thanks in advance guys and please just redirect me if this has already been asked, as I've said, I don't know how to circumscribe this question.
Yes, the memory will be freed automatically.
When a vector is destructed it will call the destructor of all the elements it contains. You didn't define a destructor for your struct so the compiler will provide a default one for you (that does nothing).
However if your vector contains pointers to objects it will be your responsibility to call the destructor on the objects before destructing the vector (because the vector will call the destructor of the pointers, not the pointed objects), if you have no other way to access them later.
See http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.11 for the answer to your question and the entire article for a very good treatment of destructors in C++.
As to your second question: yes, the memory allocated by tom[4].chuck.resize(5); will get freed as well, since it is the vector's responsibility to manage its own memory allocations (which is the case for the "resize()" call.)
Answer: Since you are not allocating the Object dynamically with the new operator, you dont have to deallocate them manually.
It's done automatically for you.
Ok. Back to your code :)
If you want to erase the 6th element then use tom.erase (tom.begin()+5) .
And if you want to erase all elements then use tom.erase (tom.begin(),tom.end() ) .
To erase the first 3 elements use tom.erase (tom.begin(),tom.begin()+3).
#include <string>
#include <vector>
using namespace std;
struct ding_t
{
std::string dang;
} foo;
struct boom_t {
std::vector <ding_t> chuck;
} bar;
int main () {
vector <boom_t> tom;
tom.resize(10);
tom[4].chuck.resize(5);
tom[4].chuck[3].dang = "jerry";
//error C2661: 'erase' : no overloaded function takes 0 parameters
//tom.erase( );
// erase the 6th element
tom.erase (tom.begin()+5);
// erase the first 3 elements:
//tom.erase (tom.begin(),tom.begin()+3);
// erase everything:
//tom.erase (tom.begin(),tom.end() );
return 0;
}
Okay, I've done this little check, just to make sure. (Why didn't I think of this earlier... was quite late yesterday... ) The initial code was badly written and didn't work, apologies for that.
This:
#include <string>
#include <vector>
struct ding_t {
std::string dang;
} foo;
struct boom_t {
std::vector <ding_t> chuck;
} bar;
int main () {
std::vector <boom_t> tom;
while (true) {
tom.resize(10);
tom[4].chuck.resize(5);
tom[4].chuck[3].dang = "jerry";
tom.erase( tom.begin(), tom.end() );
}
return 0;
}
causes no memory leak, the used memory is stable.

Simple vector program error

Hi iam new to c++ and iam trying out this vector program and i am getting the following error:
error: conversion from test*' to non-scalar typetest' requested|
Here is the code
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
class test{
string s;
vector <string> v;
public:
void read(){
ifstream in ("c://test.txt");
while(getline(in,s))
{
v.push_back(s);
}
for(int i=0;i<v.size();i++)
{
cout<<v[i]<<"\n";
}
}
};
int main()
{
cout<<"Opening the file to read and displaying on the screen"<<endl;
test t=new test();
t.read();
}
new is used to dynamically allocate memory. You don't need to do that, so just do:
test t; // create an instance of test with automatic storage
t.read(); // invoke a method
The error is because the type of new test() is a test*, a pointer to a (newly created) test. You can't assign a test* to a test.
The pointer version, for what it's worth, would have been:
test* t = new test();
t->read(); // the arrow is short for (*test).
delete t; // don't forget to clean up!
However, it's bad style to do raw memory allocation like that. You'd use something called a smart pointer to make sure it gets deleted automatically, instead. The standard library has one in the header <memory>, called auto_ptr, that would suffice:
std::auto_ptr<test> t(new test()); // put a new test into a pointer wrapper
t->read(); // treat it like a normal pointer
// nothing else to worry about, will be deleted automatically
However, all this isn't needed for you, in this case. Always prefer automatic (stack) allocation over dynamic allocation.
Change
test t=new test();
t.read();
to
test *t=new test();
t->read();
t should be a pointer to type test. And to access a class member using a pointer we use the -> operator. Also its a good practice to delete any dynamically allocated objects as:
delete t;
new test() will return a pointer to a t so you either want to use pointer throuought or create t on the stack
Code using pointers
test *t=new test();
t->read(); // note needs -> rather than .
delete t; // as declared n the heap you must delete
or usually better do all on the stack
test t;
t.read();

Is it possible to create a vector of pointers?

Just wondering, because of a problem I am running into, is it possible to create a vector of pointers? And if so, how? Specifically concerning using iterators and .begin() with it, ie: How would I turn this vector into a vector of pointers:
class c
{
void virtual func();
};
class sc:public c
{
void func(){cout<<"using func";}
};
sc cobj;
vector<c>cvect
cvect.push_back(cobj);
vector<c>::iterator citer
for(citer=cvect.begin();citer<cvect.end();citer++)
{
citer->func();
}
Sure.
vector<c*> cvect;
cvect.push_back(new sc);
vector<c*>::iterator citer;
for(citer=cvect.begin(); citer != cvect.end(); citer++) {
(*citer)->func();
}
Things to keep in mind:
You'll need to cleanup after your self if you use dynamically allocated memory as I did in my example
e.g.:
for(...) { delete *i; }
This can be simplified by using a vector of shared_ptrs (like boost::shared_ptr). Do not attempt to use std::auto_ptr for this, it will not work (won't even compile).
Another thing to keep in mind, you should avoid using < to compare iterators in your loop when possible, it will only work for iterators that model a random access iterator, which means you can't change out your code to use e.g. a std::list.
vector <c> cvect is not a vector of pointers. It is a vector of objects of type c. You want vector <c*> cvect. and the you probably want:
cvect.push_back( new c );
And then, given an iterator, you want something like:
(*it)->func();
Of course, it's quite probable you didn't want a vector of pointers in the first place...
Yes it is possible, and in fact it is necessary to use pointers if you intend your vector to contain objects from an entire class hierarchy rather than of a single type. (Failing to use pointers will result in the dreaded problem of object slicing -- all objects are silently converted to base class type. This is not diagnosed by the compiler, and is almost certainly not what you want.)
class c
{
void virtual func();
};
class sc:public c
{
void func(){cout<<"using func";}
};
sc cobj;
vector<c*> cvect; // Note the type is "c*"
cvect.push_back(&cobj); // Note the "&"
vector<c*>::iterator citer;
for(citer=cvect.begin();citer != cvect.end();citer++) // Use "!=" not "<"
{
(*citer)->func();
}
Note that with a vector of pointers, you need to do your own memory management, so be very careful -- if you will be using local objects (as above), they must not fall out of scope before the container does. If you use pointers to objects created with new, you'll need to delete them manually before the container is destroyed. You should absolutely consider using smart pointers in this case, such as the smart_ptr provided by Boost.
Yes, sure.
// TestCPP.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
class c
{
public:
void virtual func() = 0;
};
class sc:public c
{
public:
void func(){cout<<"using func";}
};
int _tmain(int argc, _TCHAR* argv[])
{
sc cobj;
vector<c*> cvect;
cvect.push_back(&cobj);
vector<c*>::iterator citer;
for(citer=cvect.begin();citer<cvect.end();citer++)
{
(*citer)->func();
}
return 0;
}
Please note the declaration of vector<c*> cvect and the use of cvect.push_back(&cobj).
From the code provided, you are using iterator in a wrong way. To access the member an iterator is pointing to you must use *citer instead of citer alone.
You have create vector<c*> for a vector of pointers. Then use new to allocate the memory for c objects and push them into vector. Also, don't forget that you have to delete yourself and vector.clear() will not release the memory allocated for c objects. You have to store c as a vector of pointers here, otherwise the call to the virtual function will not work.
Try Boost Pointer Container Library. It has several advantages over regular vector of pointers, like:
my_container.push_back( 0 ); // throws bad_ptr
ptr_vector<X> pvec;
std::vector<X*> vec;
( *vec.begin() )->foo(); // call X::foo(), a bit clumsy
pvec.begin()->foo(); // no indirection needed