-1

我有一个这样的结构:

struct foo
{
    IBar* ptr;
};

它是具有较长生命周期的 foo 对象的一部分。用户经常在不同的回调中获取这些对象的实例,有时他们在某些地方将东西注入 IBar*,在以后的回调中使用它,最终释放它。(IBarvirtual void free() { delete this; }当然可以被覆盖)。

问题是我想将我的用户转换为每个 foo 结构拥有多个的可能性,IBar*并且我想让转换顺利进行。使过渡平滑的一个想法是更改 foo 结构如下:

struct foo
{
    foo()
    {
        ptr = reinterpret_cast<IBar*>(new IBar*[N]);
        memset(ptr, 0, sizeof(IBar*)*N);
    }

    IBar*& getBarPtr(size_t offset)
    {
        return reinterpret_cast<IBar**>(ptr)[offset];
    }

    IBar* ptr;
};

我的想法是,通过这种方式,任何使用旧样式的人都应该以通常的使用方式IBar*回退到透明地使用第一个:N

someFoo.ptr = new iImplementIBar(...);

但是那些开始过渡到新用途的用户可以获得他们的抵消,而不是

someFoo.getBarPtr(myOffset) = new iImplementIBar(...);

但是,问题在于它foo有一种reset方法可以做到这一点:

void reset() {
    if (ptr)
    {
        ptr->free();
        ptr = 0;
    }
}

这个想法用这个代替:

void reset() {
    IBar** ptrs = reinterpret_cast<IBar*>(ptr);
    for (size_t i = 0; i < N; ++i)
         if (ptrs[i])
        {
            ptrs[i]->free();
            ptrs[i] = 0;
        }
}

并且free上面的功能似乎丢失了。有没有办法使这项工作?或者出了什么问题?

4

2 回答 2

0

如果您确实必须在不实现较新接口的情况下执行此操作,那么为什么不使用这样的东西:

struct foo
{
    IBar **bars; // or better yet: std::array or std::vector if size of N is fixed.
    IBar *ptr;

    IBar *getBar(int index)
    {
        ...
    }

    ...
};

这样,现有 'foo' 界面的用户可以继续使用ptr,但新bars界面也可供希望使用它的人使用。

如果不知道更多,很难知道上述设计是否有意义。

于 2012-12-04T00:48:57.943 回答
0

在不推荐使用这种复杂的手动生命周期管理设计的情况下,可以构建一个虚拟 IBar,将其转发到集合中的第一个 IBar,同时释放整个集合。

#include <iostream>
#include <new>

// existing:
struct IBar
{
    virtual void method() =0;
    virtual void free() =0;
};

struct Bar : public IBar
{
    virtual void method() { }
    virtual void free() { delete this; }
};

struct foo
{
    virtual void reset() { if (ptr) {ptr->free();}}
    IBar* ptr;
};

// proposed:
struct fooset;

struct foosetwrap : public IBar
{
    virtual void method();
    virtual void free();
    fooset* ptrOwner;
};

struct fooset : public foo
{
    fooset(IBar** begin, IBar** end) : ptrBegin(begin) , ptrEnd(end) 
        { wrapper.ptrOwner = this; ptr = &wrapper; }
    IBar** begin(){return ptrBegin;}
    IBar** end(){return ptrEnd;}
    virtual void reset() {for(auto& expired : *this) { if (!!expired) { expired->free(); }}}
private:
    foosetwrap wrapper;
    IBar** ptrBegin;
    IBar** ptrEnd;
};

void foosetwrap::method() { (*(ptrOwner->begin()))->method(); }
void foosetwrap::free() { ptrOwner->reset(); }

int wmain(int argc, wchar_t* argv[])
{
    IBar* bars[]={new(std::nothrow) Bar(),new(std::nothrow) Bar()};

    fooset set(std::begin(bars), std::end(bars));
    set.ptr->method();
    set.ptr->free();
    return 0;
}
于 2012-12-04T01:18:46.703 回答