代码之家  ›  专栏  ›  技术社区  ›  Benjamin Lindley

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

  •  0
  • Benjamin Lindley  · 技术社区  · 14 年前
    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;
    }
    

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

    这适用于普通迭代器,但不适用于插入迭代器。我怎样才能把它修好让两者都能用呢?

    2 回复  |  直到 14 年前
        1
  •  1
  •   Potatoswatter R. Martinho Fernandes    14 年前

    实际上,您需要的是一个move inputilator,用于插入输出。由于C++中不存在这种情况,因此需要一种替代方法来表示“浅”的移动,而不是“深度”的拷贝。

    对象本身中的简单状态标志不起作用,因为允许实现在实际将对象放入容器之前随机复制对象。(为了优化起见,您知道这不会,但是不用担心调试构建是很好的。)

    在我脑子里,这听起来像是一个自定义分配器的工作。默认分配器使用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 ,如果某些对象实际上已复制到容器中。

        2
  •  0
  •   skimobear    14 年前

    上面提到了正在调用一个复制构造函数。在提供的示例中,容器似乎定义为容纳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>)。