如何避免使用插入迭代器调用复制构造函数

发布于 2024-09-18 23:06:31 字数 951 浏览 1 评论 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;
}

这适用于普通迭代器,但不适用于插入迭代器。我怎样才能修复它以适用于两者?

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

I have this function, which works fine. Only problem is that I don't want to invoke the copy constructor, because it copies the entire surface, and I only need to copy the pointer. I just want to use the default constructor, then set the member _surface to temp_surface[i], like this:

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

That works for normal iterators, but not for insertion iterators. How can I fix it to work for both?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

神经暖 2024-09-25 23:06:36

据说正在调用复制构造函数。在提供的示例中,容器可能被定义为容纳 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)。

It's mentioned that a copy constructor is being called. In the example that provided it seems like the container is probably defined to hold BlitSurface. Something like std::vector< BlitSurface>. This is a guess on my part from the following lines:

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

My understanding is that all std containers will make a copy upon insert. From there on you can use the objects in the container by reference. If you do not want the copy constructor to be called on BlitSurface then I would suggest that the container store a pointer to BlitSurface. This way when the container does its copy on insert the object it actually makes a copy of is a pointer (not the BlitSurface object that is pointed to).

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

Keep in mind that that this approach allocates on heap (i.e. new) so memory will have to be explicitly deleted later or some type of smart pointer can be used in the container to take care of the deletion (std::vector< boost::shared_ptr< BlitSurface> > ).

心如荒岛 2024-09-25 23:06:34

您真正想要的是与插入 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 移动是完全可以的。

Really what you want is a move InputIterator for use with the insertion OutputIterator. Since that doesn't exist in C++03, there needs to be an alternative way to signal that a "shallow" move, not a "deep" copy, is desired.

A simple state flag in the object itself won't work, because the implementation is allowed to copy the object around randomly before actually putting it in the container. (For optimization's sake, you know it won't, but it's nice not to worry about debug builds.)

Off the top of my head, it sounds like a job for a custom allocator. The default allocator copy-constructs using placement new; you can define an alternate constructor and call it using placement new instead.

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

Of course, it's perfectly fine to add state to BlitSurface to disable moving by move_obj, if some objects are in fact copied into the container.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文