I'm looking for a method to dynamically create new class objects during runtime of a program. So far what I've read leads me to believe it's not easy and normally reserved for more advanced program requirements.
What I've tried so far is this:
// create a vector of type class
vector<class_name> vect;
// and use push_back (method 1)
vect.push_back(*new Object);
//or use for loop and [] operator (method 2)
vect[i] = *new Object;
neither of these throw errors from the compiler, but I'm using ifstream to read data from a file and dynamically create the objects... the file read is taking in some weird data and occasionally reading a memory address, and it's obvious to me it's due to my use/misuse of the code snippet above.
The file read code is as follows:
// in main
ifstream fileIn
fileIn.open( fileName.c_str() );
// passes to a separate function along w/ vector
loadObjects (fileIn, vect);
void loadObjects (ifstream& is, vector<class_name>& Object) {
int data1, data2, data3;
int count = 0;
string line;
if( is.good() ){
for (int i = 0; i < 4; i++) {
is >> data1 >> data2 >> data3;
if (data1 == 0) {
vect.push_back(*new Object(data2, data3) )
}
}
}
}
vector<Object> vect;
vect.push_back(Object()); // or vect.emplace_back();
That's it. That is the correct way, period. Any problems you are describing with reading objects from a file are a seperate matter, and we'd need to see that code in order to help you figure out what is wrong.
If you need polymorphism, then use a smart pointer:
vector<unique_ptr<Base>> vect;
vect.emplace_back(new Derived);
If you are, for some reason, constrained from using smart pointers, the old fashioned, error prone way to do it is like this:
vector<Base *> vect;
vect.push_back(new Derived);
....
for (int i=0; i<vect.size(); ++i)
{
delete vect[i];
vect[i] = NULL;
}
This is, of course, not exception safe.
If you absolutely have to use pointers (your objects store large data sets internally) then you should change your code to:
// create a vector of type class
vector<class*> vect;
// and use push_back (method 1)
vect.push_back(new Object);
//or use for loop and [] operator (method 2)
vect[i] = new Object;
Keep in mind that you'll have to delete your objects at some point.
vector<classType> vect;
declares vector container which contains type of classType, but you are adding a pointer to classType into vect, which will make compiler unhappy indeed.
If you need to present object's polymorphism in vector container, you need to store pointer to object, change your vect type to:
vector<std::shared_ptr<classType> > vect;
Declaring dynamic objects uses the following format:
TypeName * Name = new TypeName
you're going a little to fast with your vector, what you need to do is create a new object of class Object, THEN push it into the vector.
Object * MyObj = new Object //allocate space for new object
vect.push_back(MyObj) //push back new object
REMEMBER to delete what ever you allocate, which means looping through each element at the end to delete its member:
for(int i = 0; i < vectLen; i++) //probably will be replaced with iterators for vectors
{
delete vect[i];
}
read up on dynamic allocation more in depth here
Related
I have this class:
class aa
{
public:
int i = 0;
~aa(){
std::cout << "killin in the name of" << std::endl;
}
};
And I want to make a vector of this class. First I thought o reserving the needed size:
int main()
{
std::vector<aa> vec;
vec.reserve(2);
vec[0] = *(new aa());
vec[1] = *(new aa());
//use the vector
vec.clear();
return 0;
}
But the destructor was not called.
On the other side, when I fill the Vector using push_back
int main()
{
std::vector<aa> vec;
vec.push_back(*(new aa()));
vec.push_back(*(new aa()));
//use the vector
vec.clear();
return 0;
}
I actually get the destructor called.
Why?
A std::vector already does this memory management for you.
When you use an std::vector with simple classes like this, you do not need any new or delete calls.
reserve
Under the hood, reserve is just making sure that a chunk of memory is preallocated to hold the specified number of member variables.
resize
Under the hood, resize will actually create n new objects. You do not need to explictly call new.
Your example
The code *(new aa()) will create a new aa object on the heap. When you write vec[0] = *(new aa()); it will attempt to copy the contents of your new object to the object that lives in the address vec[0]. Thus there are 2 distinct objects alive at this point in time ... one object vec[0] at one place in memory, and one object elsewhere in memory.
What's worse is that you have now called new and never deleted that object. You thus have a memory leak.
What you probably want
Almost certainly, what you will want one of these scenarios.
Create a vector, and then resize it to have n elements. Then use those elements:
int main() {
std::vector<aa> vec;
vec.resize(2);
vec[0].i = ...;
vec[1].i = ...;
//use the vector
return 0;
}
push_back elements when you want to add things
int main() {
std::vector<aa> vec;
vec.push_back(aa()); // Creates a new aa instance and copies into the vector
aa obj;
vec.push_back(obj); // Copies the existing object's data into a new object in the vector.
//use the vector
return 0;
}
The destructor of vector will delete all of the memory appropriately. No need to explicity clear in this example.
There are more advanced ways that you can use vector, but until you understand this code, you probably should just stick to these basics.
This isn't the code I'm working on but it's the gist of what I want to do.
object *objects; int totalObjects;
void addObject(object o)
{
objects[totalObjects] = o;
totalObjects++;
}
It's giving me an access error when I try this:
Unhandled exception at 0x00e8a214 in crow.exe: 0xC0000005: Access violation writing location 0xcccccccc
Am I going to have to use 'new' and if so do I have to create a new array to copy to every time? Can I just add or take elements from the array I'm using?
Why don't you just use std::vector?
std::vector<object> objects;
void addObject(object o)
{
objects.push_back(o);
}
..or
void addObject(const object &o)
{
objects.push_back(o);
}
to remove additional copying.
When it comes to implementing your own dynamic array without std::vector, Yes. you need to allocate new memory, and copy your array to new memory block. Here's my example code with malloc and placement new.
#include <stdlib.h> // for malloc/free
#include <new> // for placement new, std::bad_alloc
object *objects = nullptr;
size_t totalObjects = 0;
void addObject(const object &o)
{
object *old_objects = objects;
size_t old_size = totalObjects;
size_t new_size = totalObjects + 1;
object *new_objects = (object *)malloc(sizeof(object) * new_size);
if (new_objects == nullptr)
throw std::bad_alloc();
size_t i;
try
{
for (i = 0; i < old_size; ++i)
{
new (&new_objects[i]) object(old_objects[i]); // placement new
}
}
catch (...)
{
// destroy new_objects if an exception occurs during creating new_objects
for (size_t j = 0; j < i; ++j)
{
new_objects[i].~object();
}
free(new_objects);
throw;
}
objects = new_objects;
free(old_objects);
}
(I haven't tested the code yet >o<)
Note that I used malloc and placement new, not new operator. It's impossible to call copy constructor of each element of the dynamic array with array-new.
However, if your object is TriviallyCopyable, you can use realloc. It can be more efficient, because realloc can just expand memory block, without copying - if the memory is enough.
..And you can select multiple lines and just press TAB in Visual Studio (..or many other editors).
You declared an object pointer, but not yet allocated the actual memory to store object objects. Your assignment statement merely tries to copy the input object o into an unallocated array member.
This is why you should use new before the assignment. The new operator asks the system to allocate some memory in the required size, then return the address of that memory and assign it to the pointer. Then, the pointer points to that newly allocated memory and the assignment (or copying) can be made.
When you finished using the array space, you should free the allocated memory using delete.
Okay, I'm going to add an answer to my own question. Let me know if this is bad etiquette. I just wanted to post some of my own code to duel with yours.
#include <vector>
std::vector<object> objects;
okay so I want to have two arrays (vectors) for the objects and double for distances so I may end up with
std::vector<double> distances;
void swap(unsigned int a, unsigned int b)
{
objects.swap_ranges(a,b);
distances.swap_ranges(a,b)
}
I'm going by the cplusplus.com reference for this function so let me know if I have it wrong. I'm going to go through it and completely redo my code.
Is there a type like the matrix that will let me hold data of different types so I don't have to invent a new object to handle each one individually?
If what you wrote is the most efficient and fast way to do this then I'll make a new class to hold both items.
thanks :)
I want to create an unknown number of objects each with a specific object name inside the main-method at runtime. The objects should be existent until the program ends (main-method ends). Note, that in my case the objects are Fields.
I thought about a solution like this:
for ( i=1 ; i <= NumberOfObjects ; i++)
{
if (i==1)
{
MyClass *ObjectName1 = new MyClass();
}
if (i==2)
{
MyClass *ObjectName2 = new MyClass();
}
. //more if statements for more objects
.
.
} //for loop closed
Questions:
I don't think this solution is good, since the number of created objects still would be limited to the if-statements within the for-loop. Any better solutions?
Scope of pointers in loops: When the if-blocks are exited the pointers are out of scope. How can I access the with "new" created objects afterwards?
Named variables are removed once the code is compiled and doesn't mean anything to you afterwards.
Looks like you need a look up table, use an std::map or std::unordered_map with string key as the name of the object.
std::map<std::string, MyClass*> variablesTable;
for ( i=1 ; i <= NumberOfObjects ; i++)
{
std::ostringstream oss << "name" << i;
variablesTable[oss.str()] = new MyClass(); //you actually need to check if it exists, otherwise will be overwritten.
}
As if you want each created to run a separate code for each object, you can have a table of function objects (or just store both in a tuple) like this std::map<std::string, std::<MyClass, Func>>.
If you want to lookup just use,
MyClass* object = variablesTable[strName];
object->CallFunction();
P.S. A known trick for hash_maps is to run script before building the project to convert any literal string to int, because comparing int is faster than strings. At least I know this was used in the Uncharted series (but hardly relevant to your case).
To elaborate on your approach, there is no need for a loop. You can simplify this to
MyClass *ObjectName1 = new MyClass();
MyClass *ObjectName2 = new MyClass();
MyClass *ObjectName3 = new MyClass();
...
The scope and the lifetime of the pointer already ends, when you leave the if statement. To access the pointers outside the if/for statements, you have to move them before the loop.
I would just use a std::vector of objects
std::vector<MyClass*> objects;
for (int i = 1; i <= NumberOfObjects; i++) {
MyClass *p = new MyClass();
objects.push_back(p);
}
This won't give you an individual name for each object, but is maintainable at least.
Update:
To address the concerns of leaking memory, you can also create the objects directly in the vector without an explicit new
std::vector<MyClass> objects;
for (int i = 1; i <= NumberOfObjects; i++)
objects.push_back(MyClass());
This will give you the objects and they will be cleaned automatically, when the scope of the vector ends.
You will need something to store that objects. For example you could use a std::vector, or a std::map. You can store an unlimited number of objects (actually you're limited by your memory amount, let's say almost unlimited) inside these data structures, without caring about the memory since it's managed automatically.
EDIT: OK, that's not an answer. OP wants arbitrary object count at run time!
That question may be a template meta programming one.
Use a vector to store the pointer, use a macro to define a new pointer and push it to the vector.
Before ending, use the vector to free.
#include <vector>
#define DEFVAR( varname ) \
foo* varname = new foo(); \
v.push_back( varname )
class foo {};
int main() {
std::vector<foo*> v;
DEFVAR( ObjName1 );
DEFVAR( ObjName2 );
DEFVAR( ObjName3 );
DEFVAR( ObjName4 );
[ .... ]
for ( size_t index = 0; index < v.size(); ++index ) delete v[ index ];
return 0;
}
In my C++ code I have a class Object equipped with an id field of type int. Now I want to create a vector of pointers of type Object*. First I tried
vector<Object*> v;
for(int id=0; id<n; id++) {
Object ob = Object(id);
v.push_back(&ob);
}
but this failed because here the same address just repeats itself n times. If I used the new operator I would get what I want but I'd like to avoid dynamic memory allocation. Then I thought that what I need is somehow to declare n different pointers before the for loop. Straightforward way to this is to declare an array so I did this :
vector<Object*> v;
Object ar[n];
for(int i=0; i<n; i++) {
ar[i] = Object(i);
}
for(int i=0; i<n; i++) {
v.push_back(ar+i);
}
Is there still possibility to get a memory leak if I do it this way? Also going through an array declaration is a bit clumsy in my opinion. Are there any other ways to create vector of pointers but avoid manual memory management?
EDIT: Why do I want pointers instead of just plain objects?
Well I modified the original actual situation a bit because I thought in this way I can represent the question in the simplest possible form. Anyway I still think the question can be answered without knowing why I want a vector of pointers.
Actually I have
Class A {
protected:
vector<Superobject*> vec;
...
};
Class B: public A {...};
Class Superobject {
protected:
int id;
...
}
Class Object: public Superobject {...}
In derived class B I want to fill the member field vec with objects of type Object. If the superclass didn't use pointers I would have problems with object slicing. So in class B constructor I want to initialize vec as vector of pointers of type Object*.
EDIT2
Yes, it seems to me that dynamic allocation is the reasonable option and the idea to use an array is a bad idea. When the array goes out of scope, things will go wrong because the pointers in vector point to memory locations that don't necessarily contain the objects anymore.
In constructor for class B I had
B(int n) {
vector<Object*> vec;
Object ar[n];
for(int id=0; id<n; id++) {
ar[id] = Object(id);
}
for(int id=0; id<n; id++) {
v.push_back(ar+id);
}
}
This caused very strange behavior in objects of class B.
In this loop:
for(int id=0; id<n; id++) {
Object ob = Object(id);
v.push_back(&ob);
}
You are creating n times Object instance on stack. At every iteration there is created and removed element. You can simply avoid this using that:
for(int id=0; id<n; id++) {
Object* ob = new Object(id);
v.push_back(ob);
}
thanks that every new element exist on heap not on the stack. Try to add to in class Object constructor something like that:
std::cout<<"Object ctor()\n";
and the same in the destructor:
std::cout<<"Object dtor()\n";
If you dont want to create these objects with "new" try reason written by #woolstar
Your question about memory leaks makes me think you are worried about the lifecycle and cleanup of these objects. I originally proposed shared_ptr wrappers, but C++11 gave us unique_ptr, and C++14 filled in the missing make_unique. So with all that we can do:
vector<unique_ptr<SuperObject>> v ;
Which you create in place with the wonderfulness of perfect forwarding and variadic templates,
v.push_back( make_unique<Object>( ... ) ) ;
Yes you are going to have to live with some heap allocations, but everything will be cleaned up when v goes away.
Someone proposed a boost library, ptr_container, but that requires not only adding boost to your project, but educating all future readers what this ptr_container is and does.
No there is no memory leak in your version. When the program leaves your scope the vector as well the array are destroyed. To your second question: Why not simply store the objects directly in an vector?
vector<Object> v;
for(int i = 0; i < n; i++)
{
Object obj = Object(i);
v.push_back(obj);
}
I have a vector with raw pointers (no, I cannot use smart pointers) and I want to add items to the list in a for loop. I've made a little trial project, and I wondered if this is considered good C++ code in terms of pointer management.
Please only consider raw pointer management, I am not interested in smart pointers for this particular problem I'm trying to solve.
A simple object:
class Request
{
public:
std::string name;
};
std::vector<Request*> requests;
for (int i = 0; i < 5; i++)
{
std::stringstream ss;
ss << "elemenent ";
ss << i;
std::string s = ss.str();
Request* req = new Request();
req->name = s;
requests.push_back(req);
}
EDIT:
So the problem I am trying to solve is adding the DOMNode* to a vector from this library.
I'm starting to get the feeling that trying to write a wrapper for the parts I need from this library for my project, is a bad idea. Or maybe the library is no good?
I haven't got it to work properly using smart_ptr, if anybody out there has, then I'd like to hear about it.
Well, this leaks memory, so it is bad. Can you use a Pointer Container?
The reason this code leaks is because you create objects on the heap using new, but you never call delete on them.
As for you comment, if you have an object that manually manages some resource, you need The Big Three.
I'll consider that you have a loop, at the end of the method, to call delete on each member of the vector.
There are still issues, specifically exception safety issues.
If anything throws between the creation of the Request and its registration in the vector, you've lost the memory. One solution is to temporarily use a scoped_ptr to hold on the memory, push_back with ptr.get() and then call the release method since now the memory is owned by the vector.
If anything throws between the point when you have created the items in the vector and the point you destroy them, you need to catch the exception, destroy the items, and then rethrow.
There might be others, but RAII has been invented for a reason, it's really difficult to do without (correctly...)
If you cannot use smart pointers, then use boost::ptr_vector.
Note that if you are using TinyXml, memory management in XmlNode is probably dictated by the library - recent history iirc is that many of your problems are associated with properly understanding the memory ownership and release paradigm for this library.
What memory management do I need to cleanup when using TinyXml for C++?
What is the best open XML parser for C++?
If you are not able (or allowed) to use smart pointers, probably you could make use of a simple memory manager like this:
template <class T>
class MemManager
{
public:
typedef std::vector<T*> Vec;
~MemManager ()
{
size_t sz = v_.size ();
for (size_t i = 0; i < sz; ++i)
delete v_[i];
}
T* pushNewObject ()
{
T* t = NULL;
try
{
t = new T;
if (t != NULL)
v_.push_back(t);
}
catch (std::bad_alloc& ex) { /* handle ex */ }
return t;
}
const Vec& objects() const { return v_; }
private:
Vec v_;
};
// test
{
MemManager<Request> mm;
for (int i = 0; i < 5; i++)
{
std::stringstream ss;
ss << "elemenent ";
ss << i;
std::string s = ss.str();
Request* req = mm.pushNewObject();
req->name = s;
}
} // all Request objects will be deleted here when
// the MemManager object goes out of scope.
A quick improvement could be to derive a class RequestVector from std::vector<Request*>, add a ClearRequests method (which deletes all the Request objects and clears the vector) and and make it's destructor call ClearRequests.
(Actually aggregating the vector in RequestVector could be a better choice, but a derived class is faster done).