Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使单个指针指向指针数组,并对C++;_C++_Pointers_Memory Management - Fatal编程技术网

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;
}