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

これは通常のイテレータでは機能しますが、挿入イテレータでは機能しません。両方で機能するように修正するにはどうすればよいですか?

4

2 に答える 2

1

本当に必要なのは、挿入 OutputIterator で使用する移動 InputIterator です。これは C++03 には存在しないため、「深い」コピーではなく「浅い」移動が必要であることを知らせる別の方法が必要です。

オブジェクト自体の単純な状態フラグは機能しません。実装では、オブジェクトを実際にコンテナーに入れる前にランダムにコピーすることが許可されているためです。(最適化のために、そうならないことはわかっていますが、デバッグ ビルドについて心配しないでください。)

私の頭の中では、カスタム アロケーターの仕事のように思えます。デフォルトのアロケータは、placement new を使用してコピー構築します。代替コンストラクターを定義し、代わりに配置 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
    }
}

もちろん、一部のオブジェクトが実際にコンテナーにコピーされている場合は、状態を BlitSurface に追加してによる移動を無効にしてもまったく問題ありません。move_obj

于 2010-09-12T09:19:07.917 に答える
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> > )。

于 2010-09-12T06:44:14.373 に答える