2012-12-04 53 views
-1

我有這樣一個一個結構:單張指針指向指針數組,並通過兩個C++

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在上面的功能似乎失去了。有沒有辦法做到這一點?或者出了什麼問題?

+7

這只是毛病。爲什麼不嘗試更現代的C++構造,比如'std :: vector <>'和'std :: shared_ptr <>'? – GManNickG

+0

-1對於攻擊性內容(我懷疑是一般的釣魚)。 –

+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) 
    { 
     ... 
    } 

    ... 
}; 

這樣,現有的「富」界面的用戶繼續使用ptr但新bars界面也適用於那些希望使用它的人。

不知道更多,很難知道上述設計是否有意義。

+0

這就是我最初做的......最終上述想法會轉向這個,IBar *將完全消失。上面的「黑客」只是我想知道是否有一種方法可以讓兩個用例的IBar *工作,儘管它看起來多麼醜陋,只有在過渡期間。 –

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