-6

i write a handle class using C++. But when i run my code, i met an error.

#pragma once

#include <iostream>
using std::cout;
using std::endl;

class BaseItem{
public:
    virtual BaseItem* clone()
    {
        return new BaseItem(*this);
    }
    virtual void sayHello()
    {
        cout<<"Hello, I am class BaseItem!"<<endl;
    }
};

class ChildItem:public BaseItem{
public:
    ChildItem* clone()
    {
        return new ChildItem(*this);
    }
    void sayHello(){
        cout<<"Hello, I am class ChildItem!"<<endl;
    }
};


template <typename T>
class Handle
{
public:
    Handle():baseItem(NULL), refCount(new size_t(0)) {}
    Handle(T& object):baseItem(object.clone()), refCount(new size_t(1)) {}

    Handle(const Handle<T>& other):baseItem(other.baseItem), refCount(new size_t(1)) {}

    Handle& operator= (const Handle<T>& other)
    {
        ++*other.refCount;
        dec_count();
        baseItem = other.baseItem;
        refCount = other.refCount;
        return *this;
    }

    const T* operator->() const {return baseItem;};
    const T& operator*() const {return *baseItem;};

    T* operator->() {return baseItem;};
    T& operator*() {return *baseItem;};

    virtual ~Handle(void)
    {
        dec_count();
    }
private:
    T *baseItem;
    std::size_t* refCount;
    void dec_count()
    {
        if (-- *refCount == 0 && baseItem != NULL)
        {
            delete baseItem;
            delete refCount;
        }
    }
};

This is the main function :

int _tmain(int argc, _TCHAR* argv[])
{
    BaseItem item1;
    ChildItem item2;

    vector<Handle<BaseItem> > vec;
    vec.push_back(Handle<BaseItem>(item1));
    vec.push_back(Handle<BaseItem>(item2));

    //for (vector<Handle<BaseItem> >::iterator iter = vec.begin();
    //  iter != vec.end(); iter++)
    //{
    //  
    //}
    return 0;
}

when i run the code, the code crashed. i have no idea to debug the code. This is the error: enter image description here

4

3 回答 3

1

您的 Handle 的副本 c-tor 无效。它应该是这样的:

Handle(const Handle<T>& other)
  : baseItem(other.baseItem),
    refCount(other.refCount)
{
    ++*refCount;
}

http://ideone.com/DB7L9p

于 2013-09-12T09:58:15.073 回答
1

我能看到的问题是:

  • 复制构造函数应该共享和增加引用计数,而不是创建一个新的;
  • 基类需要一个虚拟析构函数。

第一个问题在将句柄复制到向量后导致双重删除。两个副本都认为它们是对该对象的唯一引用,因此都试图删除它。这可能是崩溃的原因。

修复这些后,您的代码似乎可以正常运行。如果您仍然有问题,我建议您使用调试器逐步检查失败的测试用例。

于 2013-09-12T09:59:39.847 回答
0

引用计数应该是实际对象的一部分,而不是Handle的一部分。句柄应该只增加和减少引用计数并且它应该创建一次。

template <typename T>
class RefCounted
{
    public:
        std::size_t refCount;
};

class BaseItem : public RefCounted<BaseItem> {

因此,所有可与Handle一起使用的类都应派生自 RefCounted。

template <typename T> class Handle
{
public:
    Handle():baseItem(NULL) {}
    Handle(T& object):baseItem(object.clone())) {++ other.refCount;}

    Handle(const Handle<T>& other):baseItem(other.baseItem) { ++ other.refCount; }

    Handle& operator= (const Handle<T>& other)
    {
        ++ other.refCount;
        baseItem = other.baseItem;
        return *this;
    }

    const T* operator->() const {return baseItem;};
    const T& operator*() const {return *baseItem;};

    T* operator->() {return baseItem;};
    T& operator*() {return *baseItem;};

    virtual ~Handle(void)
    {
        if (baseItem != NULL && -- (baseItem->refCount) == 0)
        {
            delete baseItem;
        }

    }
private:
    T *baseItem;

};

(免责声明:它不是一个工作代码,只是试图解释这个概念)

如果您正在寻找更好的实现,请参阅http://trac.webkit.org/browser/trunk/Source/WTF/wtf/RefCounted.h

于 2013-09-12T10:21:16.073 回答