C++ 使单个指针指向指针数组,并对C++;
我有一个这样的结构:C++ 使单个指针指向指针数组,并对C++;,c++,pointers,memory-management,C++,Pointers,Memory Management,我有一个这样的结构: struct foo { IBar* ptr; }; 它是具有长生命周期的foo对象的一部分。用户经常在不同的回调中获得这些对象的实例,有时他们会在某些地方将内容注入IBar*中,在以后的回调中使用它,最终释放它。(IBar有virtualvoid free(){删除此;},当然可以覆盖它) 问题是,我希望将我的用户转换为每个foo结构有多个IBar*,并且我希望使转换顺利。使转换平滑的一个想法是如下更改foo结构: struct foo { foo()
struct foo
{
IBar* ptr;
};
它是具有长生命周期的foo对象的一部分。用户经常在不同的回调中获得这些对象的实例,有时他们会在某些地方将内容注入IBar*中,在以后的回调中使用它,最终释放它。(IBar有virtualvoid free(){删除此;}
,当然可以覆盖它)
问题是,我希望将我的用户转换为每个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;
};
但是那些开始转换到新用途的用户可以得到他们的补偿,而不是
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;
}
}
void reset(){
IBar**ptrs=重新解释铸件(ptr);
对于(尺寸i=0;ifree();
ptrs[i]=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
,但新的bar
界面也可供希望使用它的用户使用
如果不了解更多信息,就很难知道上述设计是否有意义。如果不建议使用这种复杂的手动寿命管理设计,就有可能构建一个虚拟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;
}
#包括
#包括
//现有:
结构IBar
{
虚空方法()=0;
虚拟无空洞()=0;
};
结构栏:公共IBar
{
虚空方法(){}
虚拟空释放(){删除此;}
};
结构foo
{
虚拟空重置(){if(ptr){ptr->free();}
IBar*ptr;
};
//提议:
结构fooset;
结构foosetwrap:public IBar
{
虚空法();
虚拟无空洞();
fooset*ptrOwner;
};
结构fooset:公共foo
{
fooset(IBar**begin,IBar**end):ptrBegin(begin),ptrEnd(end)
{wrapper.ptrOwner=this;ptr=&wrapper;}
IBar**begin(){return ptrBegin;}
IBar**end(){return ptrEnd;}
虚拟无效重置(){for(自动和过期:*此){if(!!过期){expired->free();}}}
私人:
食品包装;
IBar**ptrBegin;
IBar**ptrEnd;
};
void foosetwrap::method(){(*(ptrOwner->begin())->method();}
void foosetwrap::free(){ptrOwner->reset();}
int wmain(int argc,wchar_t*argv[])
{
IBar*条[]={new(std::nothrow)Bar(),new(std::nothrow)Bar();
fooset集合(标准::开始(条形),标准::结束(条形));
set.ptr->method();
set.ptr->free();
返回0;
}
这太糟糕了。为什么不尝试更多的现代C++构造,比如<代码> STD::向量< /> >和<代码> STD::SyrdypPTR <代码> -1,用于攻击内容(我怀疑一般的拖曳)。这个想法是最终将它移动到合法的双指针,在那里它可以是干净的。就像上面看起来的那样丑陋。这只是一个暂时的过渡,重点是它对图书馆的用户尽可能透明。这是我最初做的…最终上述想法会转移到这一点,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;
}