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;您可以定义一个备用构造函数并使用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
    }
}

当然,如果某些对象实际上已复制到容器中,则将状态添加到 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 回答