1

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_;
}
9
  • it sounds like your problem might be coming from the vector resizing itself when it grows. When a vector resizes it allocates new memory, copies all of it's elements to the new memory, then destroys the old elements. Do you have an appropriate copy constructor for your objects? Is it a problem to copy new objects and then destroy the old ones? These are questions that need good answers before you put the objects in a standard container. Commented May 13, 2014 at 18:14
  • In you're loop in InitGameObjects, you're creating a single Object_3D, then adding it to the vector, than changing that same object, and adding it (again), and again, and again. You need to create a new one every iteration (probably with std::make_shared, then add the resulting shared_ptr<Object_3D> to the vector instead. Commented May 13, 2014 at 18:14
  • 2
    So.. offhand is Object_3D fully Rule of Three compliant? Commented May 13, 2014 at 18:15
  • Adding my comment to @YoungJohn, that one object is probably getting destroyed, again and again. Commented May 13, 2014 at 18:15
  • @Steve I expect copies are being pushed back, not the same object over and over. Commented May 13, 2014 at 18:17

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.