【问题标题】:C++ Adding Objects with pointers into VectorC ++将带有指针的对象添加到向量中
【发布时间】:2012-10-15 23:48:25
【问题描述】:

我有一个向量,它添加了包含SDL_Surface 指针的对象作为数据成员,这意味着我必须使用复制构造函数来实现指针的深层复制。该对象释放析构函数中的表面(指针),这就是问题发生的地方。在将对象添加到向量中的那一刻(通过按下按钮)程序崩溃但是当我从析构函数中删除SDL_FreeSurface(surface)(内存泄漏)时,当我将对象添加到向量时程序不会崩溃。如何正确地将对象添加到向量中?有些人可能认为问题在于析构函数试图删除悬空指针,但错误发生在向量中创建对象时。

class Block{

  public:

     Block(int x, int y, MediaFunctions &M_Functions);

     Block(const Block& source);

    ~Block();

  private:


    SDL_Surface *block_surface_names;
    SDL_Surface *block_surface_hours;

    SDL_Surface *block_names_detected;
    SDL_Surface *block_hours_detected;

    SDL_Rect     block_rect_names;
    SDL_Rect     block_rect_hours;


    };



    ////////////////////

   Block::Block(int x, int y, MediaFunctions &M_Functions){

      block_surface_names  = M_Functions.LoadOptimizedImage("block_names.png");
      block_surface_hours  = M_Functions.LoadOptimizedImage("block_hours.png");

      block_names_detected = M_Functions.LoadOptimizedImag("block_names_detected.png");
      block_hours_detected = M_Functions.LoadOptimizedImag("block_hours_detected.png");




      block_rect_names.x = x;
      block_rect_names.y = y;
      block_rect_names.w = block_surface_names -> w;
      block_rect_names.h = block_surface_names -> h;


      block_rect_hours.x = block_rect_names.x + block_rect_names.w;
      block_rect_hours.y = block_rect_names.y;
      block_rect_hours.w = block_surface_hours -> w;
      block_rect_hours.h = block_surface_hours -> h;



     }

     //copy
     Block::Block(const Block& source) 
     {
     block_surface_names  = source.block_surface_names;
     block_surface_hours  = source.block_surface_hours;

     block_names_detected = source.block_names_detected;
     block_hours_detected = source.block_hours_detected;

     }


    Block::~Block(){
     //having this is necessary obviously- crashes program
     //removing this causes the program not to crash

     SDL_FreeSurface(block_surface_hours);
     SDL_FreeSurface(block_surface_names);

     SDL_FreeSurface(block_hours_detected);
     SDL_FreeSurface(block_names_detected);

    }


    //where the object with SDL_FreeSurface() in the dtor is added to vector - crash!
   void Control::HandleEvents(SDL_Event &event, MediaFunctions &M_Functions){

       if(event.type == SDL_KEYDOWN){
           if( event.key.keysym.sym == SDLK_a )

            //append a block instance using copy constructor
            BlockVector.push_back(Block (Block(100,100, M_Functions) ) );

       }

     }

【问题讨论】:

    标签: c++ vector constructor


    【解决方案1】:

    您的代码:

    BlockVector.push_back(Block (Block(100,100, M_Functions) ) );
    

    看起来非常不理想,它会创建不必要的数据副本,看起来需要一些时间来加载,我的意思是这个 png 在 Block::Block() 中加载。

    你能做的最好的事情就是让 BlockVector 成为:

     std::vector<boost::shared_ptr<Block>> blocks;
    

    这样您就不需要制作不必要的 Block 副本。否则,您需要在Block 类中为您的SDL_Surface* 指针添加引用计数,这也可以使用shared_ptr 和自定义删除器来完成(请看这里:make shared_ptr not use delete)。

    【讨论】:

    • shared_ptr?为什么要增加那么多开销?为什么不教他如何让Block 可移动?
    • 让 shared_ptr 完全修复崩溃?
    • @MooingDuck 是的,可移动是个好主意
    • @Unit978 它将修复此崩溃,问题是您的临时对象删除了正在复制到向量中的对象的指针。您没有给出发生崩溃的确切调用堆栈,但这可能是因为访问了这样的悬空指针,或者是因为后来销毁了这样的指针
    【解决方案2】:

    复制构造函数应该做深拷贝,但你的没有。幸运的是,您实际上根本不需要复制构造函数,只需要一个移动构造函数。

     Block::Block(Block&& source) 
     {
     block_surface_names  = source.block_surface_names;
     block_surface_hours  = source.block_surface_hours;
     source.block_surface_names = NULL;
     source.block_surface_hour = NULL;
    
     block_names_detected = source.block_names_detected;
     block_hours_detected = source.block_hours_detected;
     source.block_names_detected = NULL;
     source.block_hours_detected = NULL;
     }
    

    仅与您的问题模糊相关:

    BlockVector.push_back(Block (Block(100,100, M_Functions) ) );
    

    这会产生一个Block,然后复制那个Block,然后将一个那个块的副本推到向量上。但是,可以使用以下代码直接在向量中创建Block

    BlockVector.emplace_back(100, 100, M_Functions);
    

    如果您没有启用 C++11 的编译器,您最好使用 boost::shared_ptr 中的 vector,它比此代码更慢且更复杂,但也可以解决问题。无论哪种情况,Block 类都应该有一个已删除(或未定义)的复制构造函数。

    【讨论】:

    • 将对象直接放入矢量会有什么负面影响?
    • @Unit978:当您在vector 中插入更多数据时,只有vector 的正常负面影响,例如指向Blocks 的指针可能会失效,但与@987654333 无关@。除此之外,什么都没有。
    • “这几乎解决了这个问题” -- 不,它没有。他还需要将传入对象的指针清空。
    • @BenjaminLindley:你当然是对的,我已经习惯了unique_ptr
    • 应该使用那个。那么就不需要用户定义的移动构造函数或析构函数,只需一个自定义删除器。
    猜你喜欢
    • 2020-06-27
    • 2015-05-15
    • 2021-06-19
    • 2017-11-28
    • 2018-08-18
    • 2011-10-01
    • 1970-01-01
    • 2011-02-11
    • 2015-12-02
    相关资源
    最近更新 更多