C++ Question Get handle to vessel in different class than where it's initialised

birdman

New member
Joined
Nov 29, 2016
Messages
13
Reaction score
0
Points
0
Hey you all,:tiphat:

I am new to the orbiter-forum and programming own parts and started a few days ago. I already checked the forum for solutions. But I didn't get to solve the problem. So now I'm here and hope you can help me.

At the moment I want to create a ReentrySystem which can call values of the vessel in view.
For this I created a class ReentrySystem with its own methods.

First things first: When I compile and build the code, it shows no errors.

Now when I call the function in Orbiter, which activates the ReentrySystem it calls correctly the method defined in the ReentrySystem class, but as soon as it needs to call a value of the vessel like this:
class->GetAltitude();
Orbiter crashes. I dont really understand why. I guess that the reference to the class is NULL.
Sometimes it showed me in the DebugString the initialised parameter value 0.000, but on further execution of my test scenario, without making any changes, it crashed again :facepalm:

The function "ReentrySystem::clbkRESPreStep()" gets called in the vessel .cpp file while executing the
clbkPreStep (double SimT, double SimDT, double mjd) function.

Maybe at this point it is easier to ask how to get the handle of the vessel stored in another class so that I can get the parameteres of the vessel in view. Or if i can call the handle to the vessel in view directly?
Or is this not possible because I will get an access error, because to parts of the programm want to use the handle of the vessel?

Down below is my current try of the ReentrySystem. But i guess with this call I don't get the handle of the vessel in view.

Code:
// Header file of Reentry System

#pragma once

#include "Orbitersdk.h"

class ReentrySystem {

public:
	ReentrySystem(VESSEL3* pVes);
	~ReentrySystem();
	virtual void clbkRESPreStep();	// Called after every time step to get actual parameter data
	void GetCMAltitude();
	//inline const VESSEL3* GetVessel() const { return vessel; }

	
private:
	
	// Global variables:
	// Vessel Parameters
	// Reference

	VESSEL3* pMe;
	double myAlt;

};


Code:
// .cpp file of Reentry System

#include "ReentrySystem.h"

// Constructor of ReentrySystem
ReentrySystem::ReentrySystem(VESSEL3* pVes)
{

	// Assign reference objects to local member variables
	pMe = pVes;
	// Initialise value
	myAlt = 0;
}


// Destructor ReentrySystem
ReentrySystem::~ReentrySystem()	{
	}


void ReentrySystem::clbkRESPreStep()
{
	myAlt = pMe->GetAltitude(); // Not working
	sprintf(oapiDebugString(), "Momentane Höhe über Grund %f", myAlt);
}


I'm sorry if this is confusing. Please feel free to ask for anything I may have forgotten to add.

Thanks in advance for your answers :tiphat:


EDIT:
So as i found out. If i close the orbiter simulator by force (killing the task). I always get the value 0.00000

If I don't do that and go into debug mode. It is shown to me that I get this message:

Unhandled exception at 0x6C55C6C0 in orbiter.exe: 0xC0000005: Access violation reading location 0x00730081

So it seems like I'm getting the (un)expected NULL pointer
 
Last edited:

blacek

New member
Joined
Jan 14, 2017
Messages
1
Reaction score
0
Points
0
Hi birdman, I am new to this environment as well, and this is my first post.
It looks like either the VESSEL3 object that you are passing into your ReentrySystem constructor is either not created at the time that you are calling clbkRESPreStep(), or the object itself is being de-allocated at some point after.
First off, in general you should initialize your data members via memberwise init:
ReentrySystem::ReentrySystem() : pMe(NULL), myAlt(0.) {
Secondly, always make sure to defensively protect against NULL, so in your call to clbkRESPreStep(): add a check like this: if(pMe) myAlt=pMe->GetAltitude();

I feel there may be some timing issue here, since you are calling clbkRESPreStep() on some timer (according to your comment), and perhaps there is no VESSEL3 object fully instantiated yet.

You should review when you are starting up the timer as well...might want to wait until all relevant objects have been created, etc.

Also, if there is some multithreading involved, then there may very well be some race condition, or minimally a timing issue.

Hey birdman,
Like I said, I am absolutely new to this environment, but in just reviewing some of the SDK, I am wondering if you should be subclassing VESSEL3, rather than compositing.
My previous advice is generally good practice anyway, but consider subclassing...
 
Last edited by a moderator:

birdman

New member
Joined
Nov 29, 2016
Messages
13
Reaction score
0
Points
0
Hi blacek,

thank you for your answer.
In the meantime I solved my problem.
It was a total rookie mistake with pointer initialisation.

The problem was in the program part, which I didn't post here.

To be able to use the functions/methods of the reentry system class in the main programm, without making it a subclass of the ship class, I initialised a pointer to the reentrysystem class. But I forgot to create a new class object. So my pointer was pointing to memory cells in a random manner.
Seems like I can hardly blame it for doing so :rolleyes:

So simply I solved my problem by doing this:

Code:
// spaceshipclass.h
#include "ReentrySystem.h"

/* Spaceship class */
class spaceship : public VESSEL3 {
public:
spaceship(OBJHANDLE hVessel, int flightmodel);


private:
ReentrySystem*		reentry;		// provides data for reentry mode 
};

Code:
// spaceship.cpp
#include "spaceshipclass.h"

// Constructor
spaceship::spaceship (OBJHANDLE hVessel, int flightmodel)
	: VESSEL3 (hVessel, flightmodel){


// Part I simply forgot to implement
/* Set up the ReentrySystem*/
reentry = new ReentrySystem(this);

}


Thanks again for your answer.
You were right. Not all necessary objects were created yet, because I didn't create them at all :facepalm:

In the meantime there is a query implemented, which checks if the vessel/pointer to the vesselclass, is not NULL ;)
 

martins

Orbiter Founder
Orbiter Founder
Joined
Mar 31, 2008
Messages
2,448
Reaction score
462
Points
83
Website
orbit.medphys.ucl.ac.uk
This may be obvious, in which case please ignore, but since you mentioned that you were new to programming: after creating the reentry object dynamically in the constructor, make sure you delete it in the destructor, to avoid memory leaks.

In general it's good practice to consider the scope and lifetime of your dynamic objects and match every "new" with the corresponding "delete". It's easy to forget. Or you could use a smart pointer that takes care of deleting the object when its (last) pointer goes out of scope.
 
Top