How to delete a pointer if it is a template value? - c++

I have a template class (Node is an inner class within a BST). It's now time to free up the memory; Given that either the key or the value (or both) may be pointers, I must figure out how to free them if they are.
See an example:
~Node( void )
{
if ( is_pointer< TValue >( Value ) )
{
delete Value;
Value = NULL;
}
if ( is_pointer< TComparable >( Key ) )
{
delete Key;
Key= NULL;
}
}
The implementation behind the is_pointer< T > function works (Taken from here), however as soon as I press delete on either Key or Value, I get the following:
Error 13 error C2440: 'delete' : cannot convert from 'esc::Shader' to 'void *' c:\programming\c++\git\escalator\engine\engine\searchtree.hpp 131
Error 14 error C2440: 'delete' : cannot convert from 'esc::ShaderComparable' to 'void *' c:\programming\c++\git\escalator\engine\engine\searchtree.hpp 137
Error 12 error C2679: binary '=' : no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion) c:\programming\c++\git\escalator\engine\engine\searchtree.hpp 130
I've tried static_cast, dynamic_cast, reinterpret_cast, etc, but neither of these appear to work.
What's a good solution?

I must figure out how to free them if they are.
Don't. Really- don't. That's the user's problem- and he can supply a smart pointer if he wants this behaviour. After all, what if I want to map non-owning pointers? Or need a custom deleter?
Also, your code does not work because you compile the dead code if branches anyway, because you did not use a specialization.

It looks like you are storing copies of elements of type T instead of pointers as commonly done. If your declaration is T Value; than your Node class is normally not responsible for deleting Value object.

This really depends on what kind of software you're working on here. Unless it's some quick test and you're not going to reuse the code, then yes, don't bother distinguishing pointers from objects or arrays. But if you're writing library code and you think your component will be reused by other people, then you should take care about cleaning after yourself. STL vector has been doing this successfully since the dawn of times. Last I saw the code they've been calling a Destroy function for (First,Last) elements of the vector with an value tag passed into the function as the third argument. And if elements are just plane scalar pointers (meaning int* for instance), then destructors need not be called. Obviously the real data has been allocated by the user and only addressed of the data has been stored in a vector, so it should not be deallocated. But if it's objects that are stored in the vector (objects of a user-defined class for instance, class A, lets say), then destructors need to be called for each element in the vector ~A() and after all of them ran to the end, the contiguous memory chunk that used to store the elements should be deallocated through the use of vectors allocator. For more information you can easily open vectors implementation, it's all in the header file, look at ~vector() implementation and let that guide you.

Related

C++ - Check whether pointer in pointer array is already "filled"

I am working on a project for my University where i have to implement a Hash table. I am quite new to c++, so please forgive me if I am not specific enough or if I have completely wrong assumptions.
Soo..my main problem is that I have a so called "Bucket" which is a struct in my program and which contains a pointer array of N(template parameter) places.
struct Bucket {
T *kptr{ nullptr };
Bucket *bptr{ nullptr }; //For overflow chains (linear Hashing)
Bucket(Bucket *bptr = nullptr) : kptr(new value_type[N]),bptr(bptr) {}
~Bucket() { if(bptr) delete[] bptr; if (kptr) delete[] kptr; }
};
In my main Class named My_Set for example I have an additional Bucket *table of [1<
My first assumption was to initialize the kptr array to nullptr and then in the insert method to make something like
void insert(Bucket &bkt, T &key) {
for (int i=0; i<N, ++i) {
if (bkt.kptr[i]) { //Check on nullptr!
kptr[i] = key;
}
}
}
But that´s not possible because then kptr should be Bucket T **kptr and not Bucket *kptr as far as i understood it.
So, is there any other efficient way to check one single field of an array if it has been assigned to an Object already or not?
IMPORTANT: I am not allowed to use STL Containers, Smart Poitners and similar things which would make the whole thing much easier.
Thanks!
Check whether pointer in pointer array is already “filled”
... So, is there any other efficient way to check one single field of an array if it has been assigned to an Object already or not?
Yes: Initialize the pointer to nullptr. Then, if the pointer has a value other than nullptr, you know that it has been pointed to an object.
However, your professor is correct that your checking is inefficient. On every insert you iterate through all previously inserted objects.
That is unnecessary. You can avoid trying to check whether any of the pointers have been assigned by remembering where the next free pointer is. How can we "remember" things in algorithms? Answer: Using variables. Since you must remember for each instance of your container, you need a member variable.
Since you are using this new variable to remember the next free pointer, how about we name it next_free. Now, considering that the variable must refer to an existing object, what type should it have? A reference would be a good guess, but you must also be able to reassign it once an element is inserted. What can refer to an object like a reference, but can be reassigned? Answer: A pointer. Since this pointer is going to point to a pointer to T, what should be its type? Answer: T**. What should it be initialized to? Answer: The address of the first element of kptr. With such member, insert can be implemented like this:
void insert(T &key) { // why would there be a Bucket argument for insert?
*next_free++ = new T(key); // Note: Do not do this in actual programs. Use
// RAII containers from the standard library instead
}
then kptr should be Bucket T **kptr and not Bucket *kptr as far as i understood it.
Correct. A T* can not point to an array that contains pointers (unless T happens to be a pointer) - it can point to an array of T objects. A T** can point to an array of pointers to T.
Instead of pointers to separately allocated objects, it would be more efficient to use a flat resizable array. But since you are not allowed to use std::vector, you would then have another standard container to re-implement. So consider whether the efficiency is worth the extra work.

How push_back unique_ptr parameter onto vector of shared ptrs

I'm having a tough time pushing back a unique_ptr from my method parameter onto a vector of shared pointers.
IFCCB.h:
private:
vector<shared_ptr<IFC>> m_shpVectorIFC;
public:
void addElementVectorIFC(unique_ptr<IFC> rupIFC);
IFCCB.cpp:
void IFCCB::addElementVectorIFC(unique_ptr<IFC> rupIFC)
{
m_shpVectorIFC.push_back(std::unique_ptr<IFC>(new IFContent(rupIFC)));
}
I'm getting the error:
C2664: 'IFC::IFC(const IFC &)' : cannot convert argument 1 from
'std::unique_ptr>' to 'IFO *'
In this case, IFO is the heirarchical parent of IFC. I'm not sure why it's looking at that.
I've looked at vector info and shared_ptr info, as well as using unique_ptr with standard library containers.
Any ideas? I'm not used to working with shared_ptrs and unique_ptrs.
The problem is that push_back takes the container's value_type, which is shared_ptr<IFC>, but you are passing it a unique_ptr<IFC> and the conversion from unique_ptr to shared_ptr uses an explicit constructor and can only be done from a unique_ptr rvalue, so the argument cannot be implicitly converted to shared_ptr.
To make it work you need to use std::move to convert the unique_ptr to an rvalue and then either do the conversion to shared_ptr explicitly:
unique_ptr<IFC> p;
// ...
m_shpVectorIFC.push_back(std::shared_ptr<IFC>(std::move(p)));
Or use emplace_back instead, because that function can use explicit constructors to construct the new container element:
m_shpVectorIFC.emplace_back(std::move(p)));
I'm not convinced your code that creates a new unique_ptr is correct (why can't you just insert rupIFC into the container using either of the solutions shown above?) but if that's really what you want to do, the error you get is because you are trying to pass unique_ptr<IFC> to the IFContent constructor, which takes a IFO* not a unique_ptr<IFC>. To make that compile you need to get the raw pointer out of rupIFC:
std::unique_ptr<IFC>(new IFContent(rupIFC.get()))
However this is probably unsafe, because the pointer you passed to the IFContent constructor will be deleted at the end of the function when rupIFC is destroyed, so maybe you meant to release it:
std::unique_ptr<IFC>(new IFContent(rupIFC.release()))
N.B. as dlf's answer says, there is no point creating a unique_ptr if you just want to convert it to a shared_ptr immediately, so you could simply do:
m_shpVectorIFC.emplace_back(std::make_shared<IFContent>(rupIFC.release()));
Based on your addendum, you will need to use unique_ptr::get() to provide the IFContent constructor with the raw pointer it wants. Depending on what it does with that pointer, you may actually need to use release instead to prevent double-deletion. Also, no need to create an intermediate unique_ptr when it's just going to be converted right into a shared_ptr anyway:
void IFCCB::addElementVectorIFC(unique_ptr<IFC> rupIFC)
{
m_shpVectorIFC.push_back(std::shared_ptr<IFC>(new IFContent(rupIFC.get())));
}

Error: expected a type

I am trying to use an open source class whose .h file starts with:
template <class DT>
class FFTReal
{
public:
enum { MAX_BIT_DEPTH = 30 };
typedef DT DataType;
explicit FFTReal (long length);
...
my first creating a pointer to the class in my private section of my class:
ffft::FFTReal<double> *m_fft_object;
And then, within an initialization function, create it with
m_fft_object = new fft_object((long)(FFTWindowSize));
It is in this last line that I get the error "Error:expected a type".
I have done some searches for the error but nothing seems to match my particular problem.
Thanks
Presumably this is because fft_object is not a type. You probably meant this:
m_fft_object = new ffft::FFTReal<double>(static_cast<long>(FFTWindowSize));
I also corrected the C-style cast for you.
As noted in the comments, you should avoid using raw pointers to store object data unless you have a very good reason. Consider using a smart pointer (std::unique_ptr<ffft::FFTReal<double>>) if the data should be nullable, otherwise you can simply store an object instance as a value (ffft::FFTReal<double>). Either option will make memory leaks extremely unlikely, whereas when using new and raw pointers you have to be extremely careful to delete the allocated object when you are done with it.

Storing pointer to heap objects in an STL container for later deallocation

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.

"class std::map used without template paramaters" error

I'd have to say I'm no expert on using the STL. Here's my problem, I have a class Called LdapClientManager which maintains a number of LDAP clients that are managed by ID. The container holding the LdapClients is declared as a member variable i.e.
typedef std::map<int, LdapClient *> LdapClientMap;
LdapClientMap _ldapClientMap;
The following function fails to compile with the error:
LdapClient * LdapClientManager::getLdapClient(unsigned int templateID)
{
// Do we have an LdapClient
LdapClientMap::const_iterator it = _ldapClientMap.find(templateID);
if (it == std::map::end) {
// no existing client, lets create it
LdapClient * ldapClient = new LdapClient();
if (ldapClient == NULL) {
// TODO: handle out of memory condition
}
_ldapClientMap[templateID] = ldapClient;
return ldapClient;
}
return it->second;
}
Unfortunately I get the following error at compile time, what does it mean. I haven't found a solution in google as yet.
LdapClientManager.cc: In member function LdapClient*
LdapClientManager::getLdapClient(unsigned int)':
LdapClientManager.cc:33:template class std::map' used without template parameters
Replace std::map::end with _ldapClientMap.end().
Also, new never returns 0, it throws an exception if the allocation fails.
Note that the program can be made much shorter.
LdapClient * LdapClientManager::getLdapClient(unsigned int templateID)
{
LdapClient *& value = _ldapClientMap[templateID];
if (value == 0)
value = new LdapClient();
return value;
}
It means exactly what it says it means. std::map is a class template. It is not a class in and of itself. It needs template parameters, like you used when you defined the LdapClientMap type. Later, you say std::map::end, and the compiler says that needs parameters, too.
But you probably meant _ldapClientMap.end(). Each map has its own end; end is not a static function, so you need to call it on an instance. If it were static, you would have needed to provide template parameters, just like when you defined the type: std::map<int, LdapClient*>::end.
std::map::end() is a member function of the container instance and not a universal value, so you'll need to check the result of std::map::find() against _ldapClientMap.end().
Another couple of suggestions to improve the code:
Standard C++ containers have value semantics (they want to store the actual object and not a pointer to the object). If you really need to store pointers to LdapClients instead of the LdapClient objects themselves, I would strongly recommend wrapping them in an appropriate smart pointer like boost::shared_ptr (not std::auto_ptr, which will not work). This way, the automatic memory management of the std::map will still work and destroy the objects as intended. If you don't want to use a smart pointer or put the actual LdapClient object into the container, you will have to manually manage the objects' lifetime and call delete when appropriate to prevent memory leaks. My preference would be to change the type of the map to std::map unless the LdapClient objects are polymorphic.
Unless you are using a very out of date compiler, checking the result of regular new() against 0 or NULL will not yield any new insights as new throws a std::bad_alloc these days when it can't allocated memory for whatever reason.
Instead of using _ldapClientMap[x] = y; to insert a new element, I would use _ldapClientMap.insert(LdapClientMap::value_type(x,y)) as the latter will not overwrite an existing value for key x (which the former will do) and will return 'false' in case the key already exists in the map. That is of course if that is your intention.
LdapClientMap _ldapClientMap;
You should avoid using names with a leading underscore. Technically it is undefined behavior, even if the compiler allows it because by using it you conflict with current or future reserved names.