简体   繁体   English

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

[英]How do I avoid invoking the copy constructor with insertion iterators

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. 唯一的问题是我不想调用copy构造函数,因为它复制了整个表面,而我只需要复制指针。 I just want to use the default constructor, then set the member _surface to temp_surface[i], like this: 我只想使用默认的构造函数,然后将成员_surface设置为temp_surface [i],如下所示:

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? 我该如何解决这两种问题?

Really what you want is a move InputIterator for use with the insertion OutputIterator. 您真正想要的是与插入OutputIterator一起使用的move InputIterator。 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. 由于在C ++ 03中不存在,因此需要一种替代方法来表示需要“浅”移动而不是“深”复制。

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; 默认的分配器使用new位置复制构造。 you can define an alternate constructor and call it using placement new instead. 您可以定义一个备用构造函数,并使用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
    }
}

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. 当然,如果实际上move_obj某些对象复制到容器中,则将状态添加到BlitSurface以禁用 move_obj移动是move_obj可以的。

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. 在提供的示例中,似乎容器可能已定义为容纳BlitSurface。 Something like std::vector< BlitSurface>. 类似于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. 我的理解是,所有std容器都会在插入时进行复制。 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. 如果您不希望在BlitSurface上调用复制构造函数,则建议容器存储指向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对象)。

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

Keep in mind that that this approach allocates on heap (ie 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> > ). 请记住,这种方法在堆上分配(即新分配),因此以后必须显式删除内存,或者可以在容器中使用某种类型的智能指针来执行删除操作(std :: vector <boost :: shared_ptr <BlitSurface>>)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM