我有一个像这样的结构:
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(...);
问题是,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
的功能似乎丢失了。有没有办法让这项工作?或者出了什么问题?
答案 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;
}