CalvinWylie
CalvinWylie

Reputation: 143

adding object to a vector in a for loop

I'm trying to add some objects to a vector of the same type. In the header:

std::vector<Object_3D> balls_;

I'm trying to push objects onto the back of the vector with this code:

void S3DApp::InitGameObjects(){

    int i;
    Object_3D ball_;

    for(i = 0; i < ball_count_/2; i++){
        ball_.Init(platform_, "stripe.Obj");
        ball_.SetScale(abfw::Vector3(0.2, 0.2, 0.2));
        ball_.SetTranslation(abfw::Vector3((float)i, 1.0f, (float)i));
        balls_.push_back(ball_);
    }
}

The init function loads a model from a object file:

void Object_3D::Init(abfw::Platform& platform_, const char *filename){
    abfw::OBJLoader obj_loader;
    obj_loader.Load(filename, platform_, model_);
    mesh_instance_.set_mesh(model_.mesh());
    transform_.SetIdentity();
    mesh_instance_.set_transform(transform_);
    position_ = transform_.GetTranslation();
}

I get an error on the third run through the for loop because the object_3d destructor is called. But I'm not sure why. The destructor is where the call to Model::Release() is made I think which is on top of the call stack. This is the call stack:

s3d_app.exe!abfw::Model::Release() Line 26  C++
s3d_app.exe!Object_3D::~Object_3D() Line 9  C++
s3d_app.exe!Object_3D::`scalar deleting destructor'(unsigned int)   C++
s3d_app.exe!std::allocator<Object_3D>::destroy<Object_3D>(Object_3D * _Ptr) Line 624    C++
s3d_app.exe!std::allocator_traits<std::allocator<Object_3D> >::destroy<Object_3D>(std::allocator<Object_3D> & _Al, Object_3D * _Ptr) Line 758   C++
s3d_app.exe!std::_Wrap_alloc<std::allocator<Object_3D> >::destroy<Object_3D>(Object_3D * _Ptr) Line 909 C++
s3d_app.exe!std::_Destroy_range<std::_Wrap_alloc<std::allocator<Object_3D> > >(Object_3D * _First, Object_3D * _Last, std::_Wrap_alloc<std::allocator<Object_3D> > & _Al, std::_Nonscalar_ptr_iterator_tag __formal) Line 89    C++
s3d_app.exe!std::_Destroy_range<std::_Wrap_alloc<std::allocator<Object_3D> > >(Object_3D * _First, Object_3D * _Last, std::_Wrap_alloc<std::allocator<Object_3D> > & _Al) Line 80   C++
s3d_app.exe!std::vector<Object_3D,std::allocator<Object_3D> >::_Destroy(Object_3D * _First, Object_3D * _Last) Line 1480    C++
s3d_app.exe!std::vector<Object_3D,std::allocator<Object_3D> >::_Reallocate(unsigned int _Count) Line 1515   C++
s3d_app.exe!std::vector<Object_3D,std::allocator<Object_3D> >::_Reserve(unsigned int _Count) Line 1532  C++
s3d_app.exe!std::vector<Object_3D,std::allocator<Object_3D> >::push_back(const Object_3D & _Val) Line 1199  C++

I have tried creating the ball object as a pointer and adding it to an array of pointers. I have tried creating the ball as an object and adding it to the array as a pointer. I have tried creating the ball object within the for loop.

Edit: Object_3D code

#include <graphics/mesh_instance.h>
#include <graphics/model.h>
#include <assets/png_loader.h>
#include <assets/obj_loader.h>
#include <maths/vector3.h>


class Object_3D{
public:
    Object_3D();
    ~Object_3D();

    void Init(abfw::Platform& platform, const char*);
    void SetTranslation(abfw::Vector3 transform_);
    void SetScale(abfw::Vector3 scale_);
    void Move(abfw::Vector3 move_);
    abfw::Model& GetModel();
    abfw::MeshInstance GetMeshInstance();
    abfw::Matrix44 GetTransform();

    abfw::Vector3 position_;
private:
    abfw::Model model_;
    abfw::MeshInstance mesh_instance_;
    abfw::Matrix44 transform_;
};

cpp.

#include "Object_3D.h"

Object_3D::Object_3D(){

}

Object_3D::~Object_3D(){
    model_.Release();
}

void Object_3D::Init(abfw::Platform& platform_, const char *filename){
    abfw::OBJLoader obj_loader;
    obj_loader.Load(filename, platform_, model_);
    mesh_instance_.set_mesh(model_.mesh());
    transform_.SetIdentity();
    mesh_instance_.set_transform(transform_);
    position_ = transform_.GetTranslation();
}

abfw::Model& Object_3D::GetModel(){
    return model_;
}

abfw::MeshInstance Object_3D::GetMeshInstance(){
    return mesh_instance_;
}

void Object_3D::SetTranslation(abfw::Vector3 position_vector_){
    position_ = position_vector_;
    transform_.SetTranslation(position_);
    mesh_instance_.set_transform(transform_);
}

void Object_3D::Move(abfw::Vector3 move_){

    position_ += move_;
    transform_.SetTranslation(position_);
    mesh_instance_.set_transform(transform_);
}

void Object_3D::SetScale(abfw::Vector3 scalingVector){
    transform_.Scale(scalingVector);
    mesh_instance_.set_transform(transform_);
}

abfw::Matrix44 Object_3D::GetTransform(){
    return transform_;
}

Upvotes: 1

Views: 482

Answers (1)

WhozCraig
WhozCraig

Reputation: 66194

What is Wrong

  • You have no value initialization for your members. By the time the constructor (be it a copy-ctor, a default-ctor, a special-ctor, whatever) is finished. all member variables should be initialized in some sense.

  • You're blatantly violating the Rule of Three. You need to abide by it, as you have a resource-freeing destructor, and therefore need a resource-replicating (or at least resource-sharing) copy constructor and assignment operator.

Why Your Code Crashes

Your Object_3D class harbors dynamic resources (the model is one such resource). When you push a newly initialized object into your vector, a shallow copy of the object is made because you provide no custom copy/assignment semantics. As a result, the implicit copy-ctor provided for the class is invoked. This means once the push is complete you now have two objects that harbor dynamic resource references to the same data. When the local object in the loop is destroyed once the loop body recycles, those resources are being freed by the destructor and the copy in the vector is left with invalid resource references. Accessing those references later triggers your crash.

How To Fix It

Implement your object using the Rule of Three approach, or implement a single-ownership shared resource ideology using unique objects. The latter could be done using smart pointers and a vector of said same. I'm not familiar with the toolkit you're using, so providing hard-code solution is out of the question, but suffice it to say that either your objects must outright own their resources (and thus proper copy/assignment semantics must be coded), or a sharing mechanism must be developed to allow multiple objects to share references to the same resources and the last man out the door shuts the lights off.

How to implement that, I leave to you, but at least you know your problem.

Upvotes: 2

Related Questions