使一个指针指向一个指针数组并传递给C ++

时间:2012-12-04 00:36:42

标签: c++ pointers memory-management

我有一个像这样的结构:

struct foo
{
    IBar* ptr;
};

是foo对象的一部分,具有较长的生命周期。用户经常在不同的回调中获取这些对象的实例,有时他们会在某些地方将东西注入IBar *,在以后的回调中使用它,最终释放它。 (IBar有virtual 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(...);

问题是,fooreset方法用于执行此操作:

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的功能似乎丢失了。有没有办法让这项工作?或者出了什么问题?

2 个答案:

答案 0 :(得分: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界面也可供希望使用它的人使用。

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

答案 1 :(得分: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;
}