is it possible to have some kind of list / array / vector of different structs?
For example in MFC there are CObject and CArray but without MFC:
I can do something alike
std::vector<void*> pVec;
{
MYSTRUCT m = new MYSTRUCT;
pArr.push_back(m);
// looks fine here
}
//what is in my vector now?
Is there something that can handle it?
The obvious preferred approach is to have a std::vector<Base*> to handle polymorphic types.
If you really have completely unrelated types, as it seems to be the case, then boost::any or boost::variant type erasers might be what you are looking for :
std::vector< boost::variant<int, std::string> > vec;
vec.push_back( 21 );
vec.push_back( "hello " );
The example that you have given is dangerous. How do you clean up (i.e. delete) what you've allocated? Its type has been erased by being assigned to a void *, so how can the compiler know which operator delete to call?
You can safely go about this at least two different ways:
All the objects can inherit from a common base which has a virtual destructor. You can then make a std::vector of std::unique_ptrs to the common base. This has the advantage of being extensible (you can declare new types which derive from the common base and throw them in the container without modifying the container), but has the disadvantage of requiring that you go to the free store (to allocate memory for the std::unique_ptrs to point to).
You can use a variant type like boost::variant. This will not require a common base, or allocations on the free store, but it will require that you declare all the types that can possibly be stored in the container when you declare the container (i.e. it's not as easily extensible as an inheritance-based solution).
Related
I have came from those questions:
Why can't we declare a std::vector<AbstractClass>?
abstract classes in std containers
How to store a vector of objects of an abstract class which are given by std::unique_ptr?
They all suggested that I should use pointer or smart pointers instead.
As far as I know, Data are dynamically allocated in std::vector which means that there are pointers internally in the std::vector. So why I can not use abstract classes directly? why I have to use pointers(The one I specified) for pointers(the internally) in order to use abstract classes with std::vector. I know some features like std::vector::resize won't work. However, std::vector::reserve and std::back_inserter will solve the problem.
As far as I know, Data are dynamically allocated in std::vector which means that there is pointers internally in the std::vector
That's absolutely right. However, the pointer (actually, one of two pointers in the very common implementation) points to an array of identically-sized elements of type T, not to a single element of T or its subtype. Essentially, the pointer is used to represent an array, not to refer to a class or its subclass.
That is why you need an extra level of indirection - elements of an array T[] are not capable of storing subclasses of T without object slicing.
Data are dynamically allocated in std::vector which means that there is pointers internally in the std::vector
No, that's a misconception. std::vector allocates an array of instances internally, and you can't create an instance of an abstract class.
While it is true that memory for std::vector is allocated dynamically, the fact is that in std::vector<T> objects of type T are stored as copies. And you simply cannot copy abstract classes.
For example, if you have a base class A, a derived class B, and a std::vector<A>. Then, if you try to stored an object of type B in that vector, it will be copied and stored as an A. That is, it will be spliced.
class A {};
class B: public A {};
int main()
{
std::vector<A> as;
B b;
as.push_back(b); //<-- splice!!!
}
That, assuming that class A is copiable (and non-abstract). If it is abstract the compiler will save you the trouble and fail the declaration of the vector.
In order to insert something into a vector, the template has to first instantiate the class (since it uses the copy constructor). Since this is not possible with an abstract class, you can't do it!
Source
This may seem silly, but I'd like to make a container that holds pointers of any type, so that I can store every single pointer in there and then easily delete them later. I tried:
vector<void*> v;
v.push_back(new Dog());
v.push_back(new Cat());
cout << v[0]; // prints mem address
cout << v[1]; // prints another mem address
cout << *v[0]; // compiler yells at me
But apparently you can't dereference void pointers. Is there a way to make a generic container of pointers of any type, without having to make every single class extend a superclass called "Object" or something?
You can implement pointer wrapper a template class which inherits from a common base class and place those to the container instead. Something along the lines:
class pointer_wrapper_base
{
public:
virtual void delete_pointee()=0;
protected:
void *m_ptr;
};
template<class T>
class pointer_wrapper: public pointer_wrapper_base
{
public:
pointer_wrapper(T *ptr_) {m_ptr=ptr_;}
virtual void delete_pointee()
{
delete (T*)m_ptr;
}
};
Once you have this class, you can use poly-variant class for example, which is like variant class, but all the different variations have common base class. I have an implementation here if you want to have a look: http://sourceforge.net/p/spinxengine/code/HEAD/tree/sxp_src/core/utils.h (search for poly_pod_variant):
std::vector<poly_pod_variant<pointer_wrapper_base> > x;
x.push_back(pointer_wrapper<Cat>(new(Cat)));
x[0]->delete_pointee();
Or if you are ok with dynamic allocation for the wrappers, then you can of course just store pointers to pointer_wrap_base to the vector, e.g.
std::vector<std::unique_ptr<pointer_wrapper_base> > x;
x.push_back(std::unique_ptr<pointer_wrapper_base>(new(pointer_wrapper<Cat>)(new Cat)));
x[0]->delete_pointee();
Look into using some of Boost's classes, such as boost::any, http://www.boost.org/doc/libs/1_55_0/doc/html/any.html and their example code, http://www.boost.org/doc/libs/1_55_0/doc/html/any/s02.html
Alternately, look at Boost's variant as well.
In general, learn Boost. It will blow you away and turbo charge your C++ development.
C++ has a static type system. This means that types of all expressions must be known at compile time. The solution to your problem depends on what are you going to do with the objects.
Option 1: Have Cat and Dog derive from a class
This makes sense if all the objects have a common interface, and if you can make them to derive from a class.
std::vector<std::unique_ptr<Animal>> vec; // good practice - automatically manage
// dynamically allocated elements with
// std::unique_ptr
vec.push_back(std::make_unique<Dog>()); // or vec.emplace_back(new Dog());
vec.push_back(std::make_unique<Cat>()); // or vec.emplace_back(new Cat());
std::cout << *v[0];
Option 2: boost::any
This makes sense if the types are unrelated. For example, you storing ints and objects of your class. Obviously you can't make int derived from your class. So you use boost::any to store, and then cast it back to the type of the object. Exception of type boost::bad_any_cast is thrown if you cast to unrelated type.
std::vector<boost::any> vec;
vec.push_back(Dog());
vec.push_back(25);
std::cout << boost::any_cast<int>(vec[1]);
Also, pointers. Solution to "I want manage my memory properly" is "Don't use new and delete" These are the tools to help you doing this, in no particular order:
std::string instead of null-terminated strings
std::vector<T> instead of new T[]
std::unique_ptr<T> instead of raw pointers to polymorphic objects
...or std::shared_ptr<T> if you share them
cout << * ((Dog *)v[0]);
I'm assuming here that your Dog class is stringifiable, otherwise you'll get a different kind of error, but your type conversion problem should be solved by (Dog *) type cast.
How can one store an arbitrary number of dynamically created instances (of different types) in an STL container so that the memory can be freed later only having the container?
It should work like this:
std::vector< void * > vec;
vec.push_back( new int(10) );
vec.push_back( new float(1.) );
Now, if vec goes out of scope the pointers to the instances are destructed, but the memory for int and float are not freed. And obviously I can't do:
for( auto i : vec )
delete *i;
because void* is not a pointer-to-object type.
You could object and argue that this isn't a good idea because one can not access the elements of the vector. That is right, and I don't access them myself. The NVIDIA driver will access them as it just needs addresses (void* is fine) for it parameters to a kernel call.
I guess the problem here is that it can be different types that are stored. Wondering if a union can do the trick in case one wants to pass this as arguments to a cuda kernel.
The kernel takes parameters of different types and are collected by traversing an expression tree (expression templates) where you don't know the type beforehand. So upon visiting the leaf you store the parameter. it can only be void*, and built-in types int, float, etc.
The vector can be deleted right after the kernel launch (the launch is async but the driver copies the parameters first then continues host thread). 2nd question: Each argument is passed a void* to the driver. Regardless if its an int, float or even void*. So I guess one can allocate more memory than needed. I think the union thingy might be worth looking at.
You can use one vector of each type you want to support.
But while that's a great improvement on the idea of a vector of void*, it still quite smelly.
This does sound like an XY-problem: you have a problem X, you envision a solution Y, but Y obviously doesn't work without some kind of ingenious adaption, so ask about Y. When instead, should be asking about the real problem X. Which is?
Ok, FWIW
I would recomend using an in-place new combined with malloc. what this would do is allow you store the pointers created as void* in your vector. Then when the vector is finished with it can simply be iterated over and free() called.
I.E.
void* ptr = malloc(sizeof(int));
int* myNiceInt = new (ptr) int(myNiceValue);
vec.push_back(ptr);
//at some point later iterate over vec
free( *iter );
I believe that this will be the simplest solution to the problem in this case but do accept that this is a "C" like answer.
Just sayin' ;)
"NVIDIA driver" sounds like a C interface anyway, so malloc is not a crazy suggestion.
Another alternative, as you suggest, is to use a union... But you will also need to store "tags" in a parallel vector to record the actual type of the element, so that you can cast to the appropriate type on deletion.
In short, you must cast void * to an appropriate type before you can delete it. The "C++ way" would be to have a base class with a virtual destructor; you can call delete on that when it points to an instance of any sub-class. But if the library you are using has already determined the types, then that is not an option.
If you have control over the types you can create an abstract base class for them. Give that class a virtual destructor. Then you can have your std::vector<Object*> and iterate over it to delete anything which inherits from Object.
You probably need to have a second std::vector<void*> with pointers to the actual values, since the Object* probably hits the vtable first. A second virtual function like virtual void* ptr() { return &value; } would be useful here. And if it needs the size of the object you can add that too.
You could use the template pattern like this:
template<typename T>
class ObjVal : public Object {
public:
T val;
virtual void* ptr() { return &this->val; }
virtual size_t size() { return sizeof(this->val); }
};
Then you only have to type it once.
This is not particularly memory efficient because every Object picks up at least one extra pointer for the vtable.
However, new int(3) is not very memory efficient either because your allocator probably uses more than 4 bytes for it. Adding that vtable pointer may be essentially free.
Use more than 1 vector. Keep the vector<void*> around to talk to the API (which I'm guessing requires a contiguous block of void*s of non-uniform types?), but also have a vector<std::unique_ptr<int>> and vector<std::unique_ptr<float>> which owns the data. When you create a new int, push a unique_ptr that owns the memory into your vector of ints, and then stick it on the API-compatible vector as a void*. Bundle the three vectors into one struct so that their lifetimes are tied together if possible (and it probably is).
You can also do this with a single vector that stores the ownership of the variables. A vector of roll-your-own RAII pseudo-unique_ptr, or shared_ptr with custom destroyers, or a vector of std::function<void()> that your "Bundle"ing struct's destroyer invokes, or what have you. But I wouldn't recommend these options.
To keep the long story short, I am unable to use the container from the STL and boost library and have to create my own.
My own generic container is coded in VC++6 and I need to know how to manually allocate memory for generic types before storing it in my own container. The generic types are all struct that can contain nested struct. All struct be it nested or not will contain only primitive types like char*, int, bool etc.
For example, when you call the insert function of std::vector, internally, std::vector will automatically perform a deep cloning of the generic type before storing it.
How can I duplicate this functionality (deep cloning of generic type) in my own container?
Please provide some sample code for performing deep cloning of generic type.
The std::vector (and most std containers) just call the type's copy constructor. This may or may not "deep clone" the object, depending on what the copy constructor does.
First and for all: if you want to clone any object, all it's aggregates should be cloned, too. This means that every struct/class involved in the cloning action should implement cloning behavior.
Then: the stl uses so called value-semantics: containers will always contain their elements 'by value'. Copying means creating copies of all container elements.
So in order to achieve cloning/deep copy behavior, the copy constructors of every member of the container's element type should implement deep copy behavior. Members of pointer-to-object type should also be deep-copied (not just copying the member pointer).
Note: code is untested, probably contains tons of exception-unsafety etc... and is merely used as a shallow :) example.
struct WithPointer {
int* pint;
WithPointer( int value = 0 ) : pint( new int ) { *pint = value; }
WithPointer( const WithPointer& other ) {
pint = new int;
*pint = *other.pint;
}
~WithPointer( ) { delete pint; } // important!
}
This class can be 'deep-copied' using an stl container:
std::vector<WithPointer> v;
WithPointer wp(1);
v.push_back( wp );
std::vector<WithPointer> v2 = v;
std::vector does not perform any "deep cloning" by itself. When you insert something into std::vector, the vector allocates raw memory for the new element in the appropriate space and then creates a new element in that memory area by using direct initialization (normally through placement-new) from the element you passed to the insertion method. In other words, in order to make a copy for a class type, std::vector calls the copy-constructor of the class type. If the element type is not a class type or a class type without appropriately defined copy-constructor, the deep copy will not take place.
This is what you should do in your container type, if you want to simulate copying functionality of std::vector.
In a related question I asked about creating a generic container. Using polymorphic templates seems like the right way to go.
However, I can't for the life of me figure out how a destructor should be written. I want the owner of the memory allocated to be the containers even if the example constructor takes in an array of T (along with its dimensions), allocated at some other point.
I would like to be able to do something like
MyContainer<float> blah();
...
delete blah;
and
MyContainer<ComplexObjectType*> complexBlah();
...
delete complexBlah;`
Can I do something like this? Can I do it without smart pointers?
Again, thanks for your input.
I'd recommend if you want to store pointers to complex types, that you use your container as: MyContainer<shared_ptr<SomeComplexType> >, and for primitive types just use MyContainer<float>.
The shared_ptr should take care of deleting the complex type appropriately when it is destructed. And nothing fancy will happen when the primitive type is destructed.
You don't need much of a destructor if you use your container this way. How do you hold your items in the container? Do you use an STL container, or an array on the heap? An STL container would take care of deleting itself. If you delete the array, this would cause the destructor for each element to be executed, and if each element is a shared_ptr, the shared_ptr destructor will delete the pointer it itself is holding.
You most probably do want to use smart pointers here, it really simplifies the problem. However, just as an excercise, it's quite easy to determine if given type is pointer. Rough implementation (could be more elegant, but I dont want to introduce int2type):
typedef char YesType;
typedef char NoType[2];
template<typename T>
struct IsPointer
{
typedef NoType Result;
};
template<typename T>
struct IsPointer<T*>
{
typedef YesType Result;
};
template<typename T>
struct MyContainer
{
~MyContainer()
{
IsPointer<T>::Result r;
Clear(&r);
delete[] data;
}
void Clear(YesType*)
{
for (int i = 0; i < numElements; ++i)
delete data[i];
}
void Clear(NoType*) {}
T* data;
int numElements;
};
It can be done, but this is pretty advanced stuff.
You'll need to use something like the boost MPL library (http://www.boost.org/doc/libs/1_36_0/libs/mpl/doc/index.html) so that you can get MyContainer's destructor to select the right kind of destructing it will need to do on individual items on the container. And you can use the boost TypeTraits library to decide what kind of deleting is required (http://www.boost.org/doc/libs/1_36_0/libs/type_traits/doc/html/index.html). I'm sure it will have a trait that will let you decide if your contained type is a pointer or not, and thus decide how it needs to be destructed. You may need to implement traits yourself for any other types you want to use in MyContainer that have any other specific deletion requirements. Good luck with it! If you solve it, show us how you did it.
If you don't want to go with smart pointers you can try partial template specialisation, it let's you write a template that is only used when you instatiate a container with a pointer type.
delete is used to deallocate memory previously allocated with new. You do not need to use delete here, when blah and complexBlah go out of scope they will automatically be destroyed.
While yrp's answer shows you one way of using template specialization to delete the objects contained if they are pointers, and not if they aren't, this seems like a fragile solution. If you want behavior like this you are better off using Boost Pointer Container libraries, which provide this exact behavior. The reason that the standard library doesn't is because the containers themselves don't know if they control the contained pointer or not - you need to wrap the pointer in a type that does know - ie a smart pointer.