2010-09-12 76 views
0
template<typename OutputIterator> 
void BlitSurface::ExtractFrames(OutputIterator it, 
           int frame_width, int frame_height, 
           int frames_per_row, int frames_per_column, 
           bool padding) const 
{ 
    SDL_Surface ** temp_surf = SDL_Ex_ExtractFrames(_surface, frame_width, frame_height, frames_per_row, frames_per_column, padding); 

    int surface_count = frames_per_row * frames_per_column; 

    for(int i=0; i<surface_count; ++i) 
    { 
     BlitSurface bs; 
     bs._surface = temp_surf[i]; 
     *it = bs; 
     ++it; 
    } 

    delete [] temp_surf; 
} 

我有這個函數,它工作正常。唯一的問題是我不想調用複製構造函數,因爲它複製整個表面,我只需要複製指針。我只是想使用默認的構造函數,然後設置成員_surface到temp_surface [I],如:如何避免使用插入迭代器調用複製構造函數

for(int i=0; i<surface_count; ++i) 
{ 
    it->_surface = temp_surf[i]; 
    ++it; 
} 

,對於正常的迭代器的工作原理,而不是插入迭代器。我如何解決它對兩者都有效?

+0

標準'insert_iterator'適配器被定義爲調用一些容器的'insert',這反過來,被定義爲使用拷貝構造函數 - 督察,'insert_iterator' _must_使用拷貝構造函數,每標準。所以你需要定義一個不同的適配器來減少複製的數量(如果你想使用底層容器的'insert',你可能仍然需要複製構造至少一個新構造的默認構造的項目,方法!)。 – 2010-09-12 04:31:37

+0

@Alex - 我有一個想法,但我不知道該怎麼做。我可以創建一個默認對象(_surface = NULL)。然後將其添加到容器中。在這種情況下,複製構造函數只會將_surface設置爲NULL。然後,在事實之後,我可以將對象的成員設置在容器中。但是,我再也無法使用插入迭代器了。你會知道該怎麼做嗎? – 2010-09-12 04:46:36

+0

@user,'insert_iterator'適配器的標準實現增加了'operator ='中的插入指針,所以再一次,你不能用這個特定的適配器來實現**:你需要實現_your own_專業迭代器適配器。 – 2010-09-12 04:50:34

回答

1

真的是你想要的是一個移動InputIterator用於插入OutputIterator。由於在C++ 03中不存在,所以需要一種替代方式來表示需要「淺」移動而不是「深層」移動。

的對象本身將無法工作,因爲實現被允許實際上是把它在容器繞前隨機複製對象的簡單狀態標誌。 (爲了優化的緣故,你知道它不會,但它很高興不用擔心調試版本。)

關閉我的頭頂,這聽起來像一個自定義分配器的工作。默認的分配器copy-constructs使用placement new;您可以定義一個替代構造函數並使用placement new來調用它。

template< typename T > 
struct move_traits { 
    typedef T must_copy_type; // does not exist in specializations 
}; 

template< typename T > 
struct move_if_possible_allocator 
    : std::allocator<T> { 
    typedef move_traits<T> traits; 

     // SFINAE selects this function if there is a specialization 
    void construct(typename traits::may_move_type *obj, T &value) { 
     new(obj) T(); // default construct 
     traits::move_obj(*obj, value); // custom routine 
    } 

     // SFINAE selects this function if traits is the base template 
    void construct(typename traits::must_copy_type *obj, T const &value) { 
     new(obj) T(value); // copy construct (fallback case) 
    } 

    // define rebind... exercise for the reader ;v) 
}; 

template<> 
struct move_traits<BlitSurface> { 
    typedef T may_move_type; // signal existence of specialization 
    static void move_obj(BlitSurface &out, BlitSurface &in) { 
     // fill out and clear in 
    } 
} 

。當然,這是完全罰款由move_obj到BlitSurface添加狀態禁用移動,如果一些對象實際上覆制到容器中。

+0

你的代碼對我來說是希臘語,但我理解你的解釋。到目前爲止,我已經避免處理分配器,我想是時候瞭解它們了。我現在不能有效地實施這一點,但你已經指出了我的正確方向。謝謝。 – 2010-09-12 11:21:03

0

它提到了一個拷貝構造函數被調用。在提供的例子中,似乎容器可能被定義爲保存BlitSurface。像std :: vector < BlitSurface>。這是我的一個猜測從下面幾行:

BlitSurface bs; 
    bs._surface = temp_surf[i]; 
    *it = bs; 

我的理解是,所有的std容器將插入時進行復印。從那裏你可以通過引用使用容器中的對象。如果你不想在BlitSurface上調用複製構造函數,那麼我會建議容器存儲一個指向BlitSurface的指針。這種方式,當容器做它的副本插入對象時,它實際上使得副本是一個指針(而不是指向的BlitSurface對象)。

BlitSurface* bs = new BlitSurface; 
    bs->_surface = temp_surf[i]; 
    *it = bs; 

請記住,這種做法在堆分配(即新的),所以內存則要稍後顯式刪除或某些類型的智能指針可以在容器中使用採取刪除的護理(STD :: vector < boost :: shared_ptr < BlitSurface >>)。