开发者

Call destructor via void pointer with templates

开发者 https://www.devze.com 2023-01-21 23:03 出处:网络
I wrote a class to contain my objects in it. The code is: class objectPool { private: struct itemType_{uint count; void* object;};

I wrote a class to contain my objects in it. The code is:

class objectPool
{
private:
    struct itemType_{uint count; void* object;};
    std::multimap< std::string,  itemType_ > pool_;

public:
    template<class T>
    bool addItem(std::string key, T*& object)
    {
        std::multimap< std::string,  itemType_ >::iterator
            i = pool_.find(key);
        if(i != pool_.end())
        {
            object = (T*)(*i).second.object;
            (*i).second.count++;
            return true;
        }
      开发者_开发知识库  i = pool_.insert(std::pair<std::string,itemType_>(key, (itemType_){1, NULL}));
        object = (T*)(*i).second.object;
        return false;
    }

    template<class T>
    bool removeItem(std::string key)
    {
        std::multimap< std::string,  itemType_ >::iterator
        i = pool_.find(key);
        if(i != pool_.end())
        {
            if((*i).second.count == 1)
            {
                //important to call the appropriate destructor
                delete ((T*)(*i).second.object);
                pool_.erase(i);
            }
            else
                (*i).second.count--;

            return true;
        }
        return false;
    }
};

And the test code:

#include "objectPool.h"
class testClass
{
public:
    ~testClass()
    {
        // I should get here at least once
        std::cout << "I am deleted teehee";
    }
};


    testClass* test;

    objectPool myPool;

    int main () {

        if(!myPool.addItem<testClass>("baba", test))
        {
            test = new testClass;
        }

        myPool.removeItem<testClass>("baba");
    }

For some reason my test object's destructor does not want to be invoked. First questcha: Why? Where I am wrong?

The sec.: Should I use auto_ptr instead? (Although I want to avoid using templates...)

The third.: Is there a better(-looking) solution? (with or without using templates)

The fourth.: Is there a way to invoke constructor via void pointer without templates (or without knowing the original type)?

Thanks ahead! :D And sorry for my terrific english (not my native language, although...)


You correctly store a NULL into your T* reference, but that is a reference to the local variable. When you later update that local by calling new, that has no effect on the item stored in the pool.

The easier way to fix this would be to just create the object inside the addItem function using new T.

As for your other question, a way to call the destructor without knowing the original type, there is no way to do that. But there is a trick you can use with templates. You can create a template function like the one below, and then pass around a function pointer to it.

template<typename T>
void deleter(void *ptr) 
{
    delete static_cast<T*>(ptr);
}

deleter as a simple type which you can typedef and pass around pointers:

typedef void (*deleter_func)(void *);

To get a pointer to it, just do something like this in your addItem function:

deleter_func myDeleter = &deleter<T>;

Then later:

myDeleter(somePtr);

You don't need to know the type of somePtr at the time of deletion, just need to keep a pointer to the deleter. You can also use this method with shared_ptr, which can use a deleter argument.


My guess is it's going wrong because you're inserting {1, NULL} into the map. Changing the value of test in the main function doesn't affect the content of the map.


For some reason my test object's destructor does not want to be invoked. First questcha: Why? Where I am wrong?

Your test code is wrong. You add some uninitialized pointer into the structure. Try this:

int main () {

    test = new testClass();
    if(!myPool.addItem<testClass>("baba", test))
    {
        // Duplicate, I presume...
    }

    myPool.removeItem<testClass>("baba");
}

The sec.: Should I use auto_ptr instead?

std::auto_ptr is designed for dynamically allocated local variables, it is not designed for container implementation. Your current design limits that, anyways. However, I would write the test code as

int main () {

    std::auto_ptr<testClass> test(new testClass());
    if(myPool.addItem<testClass>("baba", test.get()))
    {
        test.release();
    }
    myPool.removeItem<testClass>("baba");
}

The third.: Is there a better(-looking) solution?

Yes, there is some type-safe heterogenous container in boost. I would look at that.

The fourth.: Is there a way to invoke constructor via void pointer without templates (or without knowing the original type)?

You can use the placement new operator if you want to construct an object in pre-allocated memory. std::vector does this a lot. However, there is no way to construct an object without knowing the type. How would you specify what type's constructor to invoke? If you need this, you'll probably want to look into the factory method pattern.

0

精彩评论

暂无评论...
验证码 换一张
取 消