通过带有模板的void指针调用析构函数

时间:2010-10-24 15:07:09

标签: c++

我写了一个类来包含我的对象。 代码是:

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;
    }
};

测试代码:

#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");
    }

由于某种原因,我的测试对象的析构函数不希望被调用。 第一个问题:为什么?哪里错了?

秒:我应该使用auto_ptr吗? (虽然我想避免使用模板......)

第三个:有更好的( - 看)解决方案吗? (使用或不使用模板)

第四种:有没有办法通过没有模板的void指针调用构造函数(或者不知道原始类型)?

非常感谢! :d 对不起我非常好的英语(不是我的母语,虽然......)

3 个答案:

答案 0 :(得分:5)

您正确地将NULL存储到T *引用中,但这是对局部变量的引用。当您稍后通过调用new更新该本地时,这对存储在池中的项目没有影响。

解决此问题的更简单方法是使用new T在addItem函数内创建对象。

至于你的另一个问题,一种在不知道原始类型的情况下调用析构函数的方法,就没有办法做到这一点。但是有一个技巧可以用于模板。您可以创建一个类似下面的模板函数,然后传递一个函数指针。

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

删除作为一种简单类型,你可以输入dede并传递指针:

typedef void (*deleter_func)(void *);

要获取指向它的指针,只需在addItem函数中执行以下操作:

deleter_func myDeleter = &deleter<T>;

然后:

myDeleter(somePtr);

删除时不需要知道somePtr的类型,只需要保留指向删除器的指针即可。您也可以将此方法用于shared_ptr,它可以使用删除器参数。

答案 1 :(得分:0)

我猜是因为你将{1, NULL}插入地图会出错。更改主函数中test的值不会影响地图的内容。

答案 2 :(得分:0)

  

由于某种原因,我的测试对象的析构函数不希望被调用。第一个问题:为什么?哪里错了?

您的测试代码错误。您将一些未初始化的指针添加到结构中。试试这个:

int main () {

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

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

秒:我应该使用auto_ptr吗?

std::auto_ptr是为动态分配的本地变量而设计的,它不是为容器实现而设计的。无论如何,您当前的设计限制了这一点。但是,我会将测试代码编写为

int main () {

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

第三种:有更好的( - 看)解决方案吗?

是的,提升中有一些type-safe heterogenous container。我会看那个。

  

第四种:有没有办法通过没有模板的void指针调用构造函数(或者不知道原始类型)?

如果要在预分配的内存中构造对象,可以使用placement new运算符。 std::vector做了很多。但是,如果不知道类型,就无法构造对象。你如何指定要调用的类型的构造函数?如果您需要,可能需要查看factory method pattern