I need to create a array that holds objects from multiple classes.
Example
class baseClass
{
//
};
class first : baseClass
{
//
};
class second : baseClass
{
//
};
How do I create array that can hold first and/or second object inside it?
It is somewhat of a home-task for me so I am forced to use arrays, I already searched and know that it is done with boost libraries ans such but I have no option here guys...
The best practice for that would be to create an array of smart pointers - preferably either one of the Boost or C++11 versions - to the base class. Making it a pointer array eliminates the risk of "slicing" your objects when you access them. Using smart pointers reduces the risk of memory leaks. Making it a base class pointer means that either derived class can be stored there safely.
baseClass *array[10];
baseClass **array2 = new baseClass *[size];
This is the simplest and most dangerous way. You have to be careful about the lifetime of the objects in order to avoid leaking or double freeing. You also have to be careful with the array's allocation and deallocation, especially if you have to change the size at runtime.
std::vector<baseClass*> vec;
This improves the previous example because the vector handles the memory of the array for you, but you still have to be careful with the baseClass pointers.
std::vector<boost::variant<first,second> > vec2;
This is another improvement that eliminates the need to manually allocate or deallocate memory for the objects, and it's type safe in terms of accessing the objects as firsts or seconds. You can't mistake one kind of object for another.
std::vector<std::unique_ptr<baseClass>> vec3;
With this option you can still confuse objects of different types for each other, but it uses only the standard library and you still don't have to manage the lifetime of the objects you allocate. It does use C++11 though.
Also, if you don't need a dynamic array you can use std::array<...,size>
std::array<std::unique_ptr<baseClass>,10> array3; has absolutely zero space or time overhead at runtime over baseClass *array[10];, and is much safer. (zero overhead, assuming a decent implementation)
If you can't use libraries you need an array of pointers like:
baseClass *array[123];
array[0] = new first();
array[1] = new second();
and no slicing will occur. (don't forget to delete everything)
Related
I would like to know if I should manually release the memory reserved by std::vector and its elements in the destructor of the class that contains that vector. And if so - how exactly?
Situation #1 - std::vector of primitive types:
class A{
std::vector<int> elements;
A(){...}
};
Situation #2 - std::vector of complex types:
class B{
int b;
C * pointer;
...
};
class A{
std::vector<B> elements;
A(){...}
};
Situation #3 - std::vector of pointers to complex types:
class B{
int b;
C * pointer;
...
};
class A{
std::vector<B*> elements;
A(){...}
};
In which cases the destructor of A should be empty? In which it should look like:
A::~A(){
for(auto &e : elements){
delete e;
}
elements.clear();
}
I think about situation, when elements belongs only to A and are not shared by any other structure (when A is destroyed, the elements should also be destroyed).
It seems obvious that for std::vector of pointers, I have to use delete e on each element.
But:
Do I really have to call elements.clear(); (the object will be destroyed after that line - isn't it waste of instructions)?
Maybe I should also use erase(...) method of std::vector in loop? If so, wouldn't clear() make all the work for me instead (when the std::vector does not contains pointers)?
Did I miss something? What's the best approach?
p.s. Situation #3 is about pointers and not a shared pointers.
I would like to know if I should manually release the memory reserved by std::vector and its elements in the destructor of the class that contains that vector.
No, you never need to do that. Like any well designed RAII type, standard containers automatically destroy their contained objects when they are erased from the container (which includes erasing all the elements by destroying the container).
It seems obvious that for std::vector of pointers, I have to use delete e on each element.
Only if you're abusing the pointers to imply ownership of the objects they point to. We have smart pointers to make the ownership explicit, and automatically delete the objects at the right time.
Do I really have to call elements.clear();
No, the destructor will take care of that.
Maybe I should also use erase(...) method of std::vector in loop?
No, that would be even worse. It would invalidate the iterator used by the loop, giving undefined behaviour. The destructor will erase all the elements for you.
What's the best approach?
Store objects when you can. If you need pointers, store smart pointers if you want the container to "own" the objects, or regular pointers (or perhaps weak pointers) if you're managing the objects in some other way and just want the container to refer to them.
I'll have a large struct containing basic types, STL objects (std::string) as well as objects of a library class (which I can't modify).
struct Info {
string name;
int number;
LibClass object;
// ...
}
I'll want to stuff instances of this struct into a vector and then create a function to fill this vector.
vector<Info> list;
void addElement (string myName, int myNumber, LibClass myObject /*, ... */)
{
Info newElement = { myName, myNumber, myObject /*, ... */};
list.push_back(newElement);
}
The above code will fail, because the LibClass does not have an assigment operator specified which is needed by the vector implementation.
The code will work if I change my struct (and the addElement function parameter) to hold a pointer to a LibClass object instead. But then I would have to do memory management outside of my function (create an LibClass object on the heap for every new element).
Next best thing is to do the memory management inside the addElement function by creating a copy of the given stack object on the heap, which would keep my calling code clean. But as this code is not part of another object, I have no destructor where I could free the memory again.
Is there a way to implement this without having to do memory allocation outside of this code AND without blowing this up to be a full featured factory class?
Update: I can't modify the library class, I'm not able to use C++11 or helper libs such as boost. The structs will basically be read-only inside the vector. Even the vector will be only filled once, then only read access will happen.
If I understood everything correctly, you may think of using std::shared_ptr<>. You'll be able to allocate the library dynamically, but freeing will be done automatically.
I thought of replacing LibClass object; with std::shared_ptr<LibClass> object; and instantiating LibClass inside addElement function. Info will be copyable, because shared_ptr can move and copy itself - each copy will still hold reference to the same LibClass instance. And on the other side, when you delete all instances of a single Info item (no matter how), the shared_ptr will take care of deleting LibClass instance as well. Think of shared_ptr as a way to dynamically create class and then leave it for automatic memory management.
Since std::shared_ptr<> is part of C++11, if you cannot use the latter, you can use its equivalent from Boost: boost::shared_ptr<>. If that's also not an option, you can implement a version of shared pointer yourself - an example.
You obviously already have a copy constructor, otherwise pass-by-value would fail. So vector growth ought not to be a problem (though you may have to avoid removing elements from the start or middle of the vector).
For construction, you may use emplace_back in C++11.
I have the following code in one of my methods:
vector<Base*> units;
Base *a = new A();
Base *b = new B();
units.push_back(a);
units.push_back(b);
Should I destroy the a and b pointers before I exit the method?
Or should I somehow just destroy the units vector of pointers?
Edit 1:
This is another interesting case:
vector<Base*> units;
A a;
B b;
units.push_back(&a);
units.push_back(&b);
What about this case? Now I don't have to use delete nor smart pointers.
Thanks
If you exit the method, units will be destroyed automatically. But not a and b. Those you need to destroy explicitly.
Alternatively, you could use std::shared_ptr to do it for you, if you have C++11.
std::vector<std::shared_ptr<Base>> units;
And you just use the vector almost as you did before, but without worrying about memory leaks when the function exists. I say almost, because you'll need to use std::make_shared to assign into the vector.
A rather old-fashioned solution, that works with all compilers:
for ( vector<Base*>::iterator i = units.begin(); i != units.end(); ++i )
delete *i;
In C++11 this becomes as simple as:
for ( auto p : units )
delete p;
Your second example doesn't require pointer deallocation; actually it would be a bad error to do it. However it does require care in ensuring that a and b remain valid at least as long as units does. For this reason I would advise against that approach.
You need to iterate over the vector and delete each pointer it contains. Deleting the vector will result in memory leaks, as the objects pointed to by its elements are not deleted.
TL;DR: The objects remain, the pointers are lost == memory leak.
Yes you should destroy those pointers (assuming you aren't returning the vector elsewhere).
You could easily do it with a std::for_each as follows:
std::for_each( units.begin(), units.end(), []( Base* p ) { delete p; } );
You should not delete if this two situation match.
Created vector return to out side of the function.
Vector created outside of the function and and suppose to access from other functions.
In other situations you should delete memory pointed by pointers in vector. otherwise after you delete the pointers, no way to refer this memory locations and it calls memory leak.
vector<Base*>::iterator it;
for ( it = units.begin(); it != units.end(); ){
delete * it;
}
I would suggest that you use SmartPointers in the vector. Using smart pointers is a better practice than using raw pointers. You should use the std::unique_ptr, std::shared_ptr or std::weak_ptr smart pointers or the boost equivalents if you don't have C++11. Here is the boost library documentation for these smart pointers.
In the context of this question, yes you have to delete the pointers that are added to the vector. Else it would cause a memory leak.
You have to delete them unless you will have memory leak , in the following code if I comment the two delete lines the destructors never called, also you have to declare the destuctor of the Base class as virtual. As others mentioned is better to use smart pointers.
#include <iostream>
#include <vector>
class Base
{
public:
virtual ~Base(){std::cout << "Base destructor" << std::endl;};
};
class Derived : public Base
{
~Derived(){std::cout << "Derived destructor" << std::endl;};
};
int main()
{
std::vector<Base*> v;
Base *p=new Base();
Base *p2=new Derived();
v.push_back(p);
v.push_back(p2);
delete v.at(0);
delete v.at(1);
};
Output:
Base destructor
Derived destructor
Base destructor
Output with non-virtual base destructor (memory leak):
Base destructor
Base destructor
Yes and no. You don't need to delete them inside the function, but for other reasons than you might think.
You are essentially giving ownership of the objects to the vector, but the vector is not aware of that and therfore wont call delete on the pointers automatically. So if you store owning raw pointers in a vector, you have to manually call delete on them some time. But:
If you give the vector out of your function, you should not destroy the objects inside the function, or the vector full of pointers to freed memory would be pretty useless, so no. But in that case, you should make sure the objects are destroyed after the vector has been used outside the function.
If you don't give the vector out of the function, you should destroy the objects inside the function, but there would be no need to allocate them on the free store, so don't use pointers and new. You just push/emplace the objects themselves into the vector, it takes care of the destruction then, and therfore you don't need delete.
And besides that: Don't use plain new. Use smart pointers. Regardless what you do with them, the smart pointers will take care of a proper destruction of the objects contained. No need to use new, no need to use delete. Ever. (Except when you are writing your own low level data structures, e.g. smart pointers). So if you want to have a vector full of owning pointers, these should be smart pointers. That way you won't have to worry about wether, when and how to destroy the objects and free the memory.
The best way to store pointers in a vector will be to use smart_ptr instead of raw pointers. As soon as the vector DTOR is called and control exits the DTOR all smart_ptrs will be refernced counted. And you should never bothered about the memory leak with smart_ptrs.
In the first example, you will eventually have to delete a and b, but not necessarily when units goes out of scope. Usually you will do that just before units goes out of scope, but that is not the only possible case. It depends on what is intended.
You might (later in the same function) alias a or b, or both, because you want them to outlive units or the function scope. You might put them into two unit objects at the same time. Or, many other possible things.
What's important is that destroying the vector (automatic at scope end in this case) destroys the elements held by the vector, nothing more. The elements are pointers, and destroying a pointer does nothing. If you also want to destroy what the pointer points to (as to not leak memory), you must do that manually (for_each with a lambda would do).
If you don't want to do this work explicitly, a smart pointer can automatize that for you.
The second example (under Edit1) does not require you to delete anything (in fact that's not even possible, you would likely see a crash attempting to do that) but the approach is possibly harmful.
That code will work perfectly well as long as you never reference anything in units any more after a and b left scope. Woe if you do.
Technically, such a thing might even happen invisibly, since units is destroyed after a, but luckily, ~vector does not dereference pointer elements. It merely destroys them, which for a pointer doesn't do anything (trivial destructor).
But imagine someone was so "smart" as to extend the vector class, or maybe you apply this pattern some day in the future (because it "works fine") to another object which does just that. Bang, you're dead. And you don't even know where it came from.
What I really don't like about the code, even though it is strictly "legal" is the fact that it may lead to a condition which will crash or exhibit broken, unreproducable behaviour. However, it does not crash immediately. Code that is "broken" should crash immediately, so you see that something is wrong, and you are forced to fix it. Unluckily that's not the case here.
This will appear to work, possibly for years, until one day it doesn't. Eventually you'll have forgotten that a and b live on the current stack frame and reference the non-existing objects in the vector from some other location. Maybe you dynamically allocate the vector in a future revision of your code, since you pass it to another function. And maybe it will continue to appear working.
And then, you'll spend hours of your time (and likely the time of others) trying to find why a section of code that cannot possibly fail produces wrong results or crashes.
Warning against your second example.
This simple extension leads to undefined behavior:
class A {
public:
int m;
A(int _m): m(_m) {}
};
int main(){
std::vector<A*> units;
for (int i = 0; i < 3; ++i) {
A a(i);
units.push_back(&a);
}
for (auto i : units) std::cout << i->m << " "; // output: 2 2 2 !!!!
return 0;
}
In each loop, the pointer to each a is saved in units, but the objects that they point to go out of scope. In the case of my compiler, the memory address of each a was re-used each time, resulting in units holding three identical memory addresses -- all pointing to the final a object.
Couldn't find exact answer to the question:
Is freeing memory and allocating again the only way to reallocate memory without using cstdlib? If not so, then what are the possible solutions?
Thanks in advance.
If you are implementing your own vector class, then you do need to properly copy the contents of the vector, not use realloc, since you don't know what the object itself is doing when it is being copied (or in C++11 for relevant cases, moved). Imagine for example that you have an object that does something like this:
class B;
class A
{
private:
B* bp;
public:
A(B *p) : bp(p)
{
}
};
class B
{
public:
A a;
B() : A(this)
{
...
}
};
MyVector<B> v;
If you copy the object to a different address, without calling the constructor, the bp pointer in A will point to some "random" place. That would be a pretty nasty bug to try to find.
[And yes, there is a bunch of stuff missing in the above classes - it is not meant as a complete class declaration, etc, etc]
Perhaps you mean like what is done with a std::vector (or other container) when you load it with memory, remove all the elements, then call clear to free the memory, then allocating new items within it, thus allocating more memory? In this case, as the memory in the container grows, the container may realloc its memory as needed.
Since you mention you are creating a Vector:
In projects where we needed to do this because we did not have a vector implementation (embedded), it is common to allocate a set chunk of memory larger than what is intiially required to prevent constant memory reallocations, which incur large copy costs and cause memory fragmentation. A common scheme was to allocate a "reasonable" size for the app, then double that size if the limit is reached. If the user ever requested the buffer be reduced in size, or set to a size at initialization, then we ignore this heuristic and use the requested size.
The folowing constructor
std::vector<Object> objects(n);
creates n objects calling the default constructor, i.e. something like that:
std::vector <Object> objects;
for (unsigned int i = 0; i < n; i++) objects.push_back(o);
Is this procedure also valid for dynamically allocated objects? Does the construction
std::vector<Object *> objects(n);
represent this functionality?
std::vector <Object*> objects;
for (unsigned int i = 0; i < n; i++) objects.push_back(new Object());
If not, is there a way how to arrange it?
std::vector<Object> objects(n);
The behavior of this depends on which version of the C++ Standard your Standard Library implementation implements:
In C++03, this creates one default constructed Object and then copy constructs that object n times.
In C++0x, this default constructs n Objects.
The difference shouldn't usually matter, but it's good to know.
std::vector<Object *> objects(n);
This creates a vector with n null Object*s in it. Since Object* is not a class type and does not have a constructor, the newly inserted objects are value initialized, which for pointers means they are set to NULL.
If you want to dynamically create new objects and then store pointers to them in the container, you need to call new yourself. Note that you should not be storing raw pointers in a standard library container if the container owns the pointed-to objects. Doing so is not exception safe.
You should be using a smart pointer like shared_ptr or unique_ptr instead (note: the auto_ptr smart pointer cannot be stored in containers due to its unusual copy semantics, thus shared_ptr or unique_ptr should be used).
In any case, to insert pointers to n distinct, dynamically allocated objects into the container, you need to call new n times to create those n objects. There's nothing wrong with your for loop solution.
The folowing constructor
std::vector<Object> objects(n);
creates n objects calling the default constructor
Yes, but the default constructor is used only to construct the second optional parameter to the constructor of vector, the n objects in the vector are constructed by copying this parameter. [C++03 answer]
If you did something like:
std::vector<Object*> objects(n, new Object());
you would dynamically allocate one object and have n pointers to that object in your vector which is probably not what you want.
It is almost always a bad idea to use a container of pointers if that container is supposed to own the dynamically allocated objects. You should consider something like boost::ptr_vector, or if that is not possible a container of smart pointers (not std::auto_ptr, though).
No, the vector won't be automatically created with pointers to Object instances. You will have to perform the for loop you have written in order to populate it correctly.
You will also need to delete each of these objects when you have finished with them too.
Your final code example has the right general idea, but tread carefully: vector will not manage the allocations for you if you do that! objects.clear() will leak memory, for instance.
You probably want to use std::vector<some_smart_ptr<Object> > instead, but choosing the right smart pointer class requires care and attention to (for instance) what happens when you copy elements from one vector to another. boost::shared_ptr is a safe choice, but may have unnecessary overhead for your use case. boost::ptr_vector may be better.