Problems with wrapping Lua into a C++ class - c++

I'm using the Lua C API in C++ and I'm wrapping it into a class as follows:
class LuaScripting {
public:
lua_State *lua;
LuaScripting();
~LuaScripting();
bool execute_script(const std::string &script);
};
LuaScripting::LuaScripting() {
lua = luaL_newstate(); /* Opens Lua */
luaL_openlibs(lua); /* Opens the standard libraries */
/* Register our custom function(s) */
lua_register(lua, "write8", lua_write8);
lua_register(lua, "write16", lua_write16);
lua_register(lua, "write32", lua_write32);
lua_register(lua, "read8", lua_read8);
lua_register(lua, "read16", lua_read16);
lua_register(lua, "read32", lua_read32);
lua_register(lua, "math_sin", math_sin);
}
LuaScripting::~LuaScripting() {
lua_close(lua); /* Clean up lua */
}
I'm testing it as follows:
int main() {
// Disable buffering
setbuf(stdout, nullptr);
LuaScripting lua_scripting;
testWritingInt8(lua_scripting);
testWritingInt16(lua_scripting);
testWritingInt32(lua_scripting);
testReadingInt32(lua_scripting);
test_math_sin(lua_scripting);
return EXIT_SUCCESS;
}
The problems I'm having:
After the first testWritingInt8() the class destructor is called which will run lua_close(lua) even though the class instance didn't fall out of scope, yet. I'm not using any threads. Why is this happening?
When calling lua_close(lua) the program crashes, why?
After commenting out lua_close(lua) the write test cases run successfully but the readXX() or math_sin() return with an empty stack despite pushing a value onto the stack. Why?
Implementation:
static int math_sin(lua_State *lua) {
const auto value = luaL_checknumber(lua, 1);
const auto sine_result = sin(value);
lua_pushnumber(lua, sine_result);
return 1;
}
Test case:
void test_math_sin(LuaScripting &lua_scripting) {
std::stringstream lua_script_builder;
const auto target_value = 90.f;
lua_script_builder << "math_sin(" << target_value << ")";
const auto script_result = lua_scripting.execute_script(lua_script_builder.str());
assert(script_result == LUA_OK);
// TODO Not working
const auto read_value = (int32_t) lua_tonumber(*lua_scripting.lua, -1);
assert(target_value == read_value);
}
I'm always using the same lua_State * and I only call luaL_newstate() once.
As an attempted fix I tried to declare the lua state as a non-pointer:
lua_State lua; // error: aggregate ‘lua_State lua’ has incomplete type and cannot be defined
But doing this does not compile.
Adding another level of indirection via lua_State **lua fixes the crashing problem with lua_close() but does not fix any of the other issues.

That's because you are copying the LuaScripting object. I bet testWritingInt8 is declared like this:
void testWritingInt8(LuaScripting lua)
Notice the lua parameter is not a pointer or a reference to a LuaScripting object, it is a LuaScripting object.
So when you call testWritingInt8(lua), the computer copies the LuaScripting object into a new one, calls the function, and destroys the new one at the end the call.
Now, why does that crash? Well, your LuaScripting class doesn't have a copy constructor (LuaScripting(const LuaScripting &)) so the compiler creates a default one, which just copies all the member variables - in this case the lua pointer is copied. Then, when the new object is destroyed, it frees the Lua state.
Solution: Make it so LuaScripting objects can't be copied accidentally, by deleting the copy constructor. Also the assignment operator.
// inside LuaScripting
LuaScripting(const LuaScripting &) = delete;
LuaScripting &operator =(const LuaScripting &) = delete;
Then make sure to pass LuaScripting values by reference.
If you want to be able to move LuaScripting objects around - say, if you want to store them in a vector, but still not copy them - you can define a move constructor and move assignment operator, which are out of scope of this answer.
Your math_sin test case doesn't return any values on the stack because... your script doesn't return any values. Try return math_sin(target_value) instead of just math_sin(target_value).

Related

Problems with nested object in functional object of the tbb::flow::graph

I have a functional object that I'm using as body for multifunction_node:
class module
{
private:
bool valid;
QString description;
bool hasDetectionBranch;
tDataDescription bufData;
void* dllObject; //<-- This is a pointer to an object constructed with help of the external dll
qint64 TimeOut;
public:
module(const QString& _ExtLibName);
virtual ~module();
void operator() (pTransmitData _transmitData, multi_node::output_ports_type &op);
};
'dllObject' is created at construction time of the object 'module':
module::module(const QString& _ExtLibName) :
valid(true), hasDetectionBranch(false)
{
GetObjectDescription = (tGetObjectDescription)QLibrary::resolve(_ExtLibName, "GetObjectDescription");
CreateObject = (tCreateObject)QLibrary::resolve(_ExtLibName, "CreateObject");
DestroyObject = (tDestroyObject)QLibrary::resolve(_ExtLibName, "DestroyObject");
if (!CreateObject || !DestroyObject || !GetObjectDescription)
valid = false;
else
{
description = QString(GetObjectDescription());
dllObject = CreateObject();
}
}
And this is when 'dllObject' is destroyed:
module::~module()
{
if (valid)
{
DestroyObject(dllObject);
}
}
I've built a little graph:
void MainWindow::goBabyClicked(void)
{
module mod(QString("my.dll")); //<-- Here is OK and mod.dllObject is correct
if (!mod.isValid())
{
qDebug() << "mod is invalid!\n";
return;
}
first fir(input);
folder fol(QString("C:/out"), 10000);
graph g;
source_node<pTransmitData> src(g, fir, false);
multi_node mnode(g, tbb::flow::serial, mod); //<-- WTF? ~module() is executed!
function_node<pTransmitData> f(g, tbb::flow::serial, fol);
make_edge(src, mnode);
make_edge(mnode, f);
src.activate();
g.wait_for_all();
}
So I have 2 questions:
1) Why ~module() is executed and how to prevent this?
2) How to keep pointer for nested object correctly?
UPDATE Added some dummy code to prevent destroying dllObject at first time like:
bool b = false;
module::~module()
{
if (valid && b)
{
DestroyObject(dllObject);
}
if (!b)
b = true;
valid = false;
}
Now it works as expected but looks ugly :/
Max,
I assume you have a typedef of multi_node which is similar to the one in the reference manual example.
The constructor for the multifunction_node has the following signature:
multifunction_node( graph &g, size_t concurrency, Body body );
The body object is copied during the parameter passing and also during the construction of the node, so there are two copies of mod created during construction (actually three, as an initial copy of the body is also stored for re-initializing the body when calling reset() with rf_reset_bodies). The destructor calls you are seeing are probably those used to destroy the copies.
The body object should also have a copy-constructor defined or be able to accept the default-copy-constructor to make copies of the body. I think the QString has a copy-constructor defined, but I don't know about fields like tDataDescription. (I thought we had covered the basic requirements for Body objects in the Reference Manual, but I am still looking for the section.) In any case, the Body class must be CopyConstructible, as it is copied multiple times.
Regards,
Chris

Class properties not holding values

im working in a text-based RPG game, but when I'm setting the values to X variable, when I access that propertie again, it is in its default value, am I doing something wrong?
class Game
{
private:
bool podeAndar;
bool estaBatalhando;
Jogador _jogador;
Mapa _mapa;
public:
Game() { }
Game(Jogador _j){
_jogador = Jogador(_j.getNome());
_mapa.LoadMapa();
podeAndar = true;
estaBatalhando = false;
}
~Game(void)
{
}
Jogador getJogador() {
return _jogador;
}
void setJogador(Jogador v) {
_jogador = v;
}
}
My "Player" class
#pragma once
#include "Criatura.h"
#include <string>
class Jogador :
public Criatura
{
private:
int _cap;
public:
Jogador(std::string nome)
{
setNome(nome);
setCap(150);
}
Jogador() { }
~Jogador(void)
{
}
int getCap(){
return _cap;
}
void setCap(int v){
_cap = v;
}
}
Them my "Main" - when I set the value, when I'm following it in the debugger, it sets the value correctly, but when I access the game.getJogador().getCap() again, it has the default value 150.
int _tmain(int argc, _TCHAR* argv[])
{
Jogador _player = Jogador("Kyore");
Game game = Game(_player);
while(true){
std::cout << game.getJogador().getCap(); //print 150
game.getJogador().setCap(100); //set cap to 100
std::cout << game.getJogador().getCap(); //print 150 again
break;
}
}
In Game class, change this
Jogador getJogador() {
return _jogador;
}
to
Jogador& getJogador() {
return _jogador;
}
And add one more method only to read:
const Jogador& getJogador()const {
return _jogador;
}
Update for the questions asked in the comment
To fix your specific issue of value remaining as 150 inspite of setting a new value, converting the return type to reference is enough.
Why returning reference works?
Because, whenever your original version of getJogador() is called, a copy of the object is
created. Even though you are changing its value, you are actually
changing the value of the temporary object created, not the original
one.
So as your intention is to modify the original object, we need
to access the original one, not its temporary copy. Reference is
the better mechanism in such cases (pointer being the other mechanism, but less safer than reference)
Now about why I suggested the new over load of a const member
function, returning a const reference: this is to highlight to you that it is possible to still get the object without changing its internal state unintentionally. Your sample code does not differentiate between the two getJogador() functions.
So to understand, add these two functions to your Game class:
void DontManipulate()const { std::cout<<getJogador().getCap(); }
void Manipulate() { std::cout<<getJogador().getCap(); }
See the compiler error(s) that you get: - it should throw light on the differences.
Additionally, if you std::cout some message in both the getJogador() functions, you should be able to figure out the differences.
The problem is in your getJogador() method.
In C++, objects can be passed "by value" - which is where the program (usually) copies the object's raw data into a new location, whereas in C# and Java objects are always passed by reference (not counting C#'s structs which are passed by-value similar to C++). C++ will use the "copy constructor" to perform this copy. C++ will create the copy constructor if it isn't explicitly defined in your code, the signature has the form ClassName(ClassName& other);, the default (non-explicit) copy-constructor performs a shallow, member-wise copy operation.
In your case, your getJogador method is returning a copy of your Jogador instance field's data.
Change the method to return a reference or a pointer, like so:
Jogador& getJogador() const {
return _jogador;
}
or
Jogador* getJogador() const {
return &_jogador;
}
The const modifier informs the compiler that this method is not intended to modify the state of your Game class, so the compiler might perform certain optimizations as well as prevent successful compilation if the method does attempt to modify state.

Storing multiple Lua states in a Boost shared_ptr

I haven't used boost before, so forgive me if I am doing something silly. I have a class which holds a lua_State. I have a boost::shared_ptr vector which I push_back new states like so:
class Lua_State
{
lua_State *L;
std::string m_scr;
public:
Lua_State() : L(luaL_newstate())
{
lua_register(L, "test", test);
luaL_openlibs(L);
}
~Lua_State() {
lua_close(L);
}
inline bool LoadScript(const char* script)
{
if (!boost::filesystem::exists(script))
return false;
m_scr = fs::path(std::string(script)).filename().string();
chdir(fs::path(scr).parent_path().string().c_str());
if (luaL_loadfile(L, m_scr.c_str()))
return false;
// prime
if (lua_pcall(L, 0, 0, 0))
return false;
return true;
}
};
typedef boost::shared_ptr<Lua_State> LUASTATEPTR;
class Scripts
{
private:
std::vector<LUASTATEPTR> m_Scripts;
public:
Scripts() { }
void TestLoad()
{
m_Scripts.push_back(LUASTATEPTR(new Lua_State()));
LUASTATEPTR pState = m_Scripts[0];
pState->LoadScript("C:/test.lua");
}
};
The code works and the Lua state is added, but after a few seconds the application crashes. I am at a loss as to why this is happening. It works fine when I do it manually (without shared_ptrs and manually dereferencing).
You have violated the rule of 31. You created a non-trivial destructor and allocating constructor without disabling or writing a copy constructor and operator=.
Probably when you create the shared_ptr you are doing a copy of the above class. The temporary is then discarded and things go boom.
So, first disable LuaState::operator=(LuaState const&) and LuaState(LuaState const&) constructor (make a private non-implemented version, or in C++11 delete it), or implement it.
Next, use make_shared<LuaState>() to create your shared_ptr<LuaState> instances. This will create them "in place" and remove the copy.
1 What is this Rule of 3 I speak of? See these links: Rule of Three (Wikipedia), What is the Rule of Three?

Accessing variable outside scope of a callback c++

I have been beating my head around this issue of static versus non-static, callback functions, function pointers, etc... My goal is to access data of a struct outside the scope of my callback interface. I am trying to do this within my class called TextDetect. I thought I was on track when I asked this question: Avoiding a static member function in c++ when using a callback interface from C
However, I still can't access the data without losing scope over the data that I am most interested. At runtime, I get "Access violation reading location ..." I'll point it out below where it fails.
I implemented the answer to my previous question as the following class, shown entirely (Note: vtrInitialize is part of a 3rd party api code int vtrInitialize(const char *inifile, vtrCallback cb, void *calldata);):
class TextDetect {
const char * inifile;
vtrImage *vtrimage;
int framecount;
public:
TextDetect();
~TextDetect();
void vtrCB(vtrTextTrack *track);
static void vtrCB_thunk(vtrTextTrack *track, void *calldata);
int vtrTest(cv::Mat);
bool DrawBox(cv::Mat&);
vtrTextTrack *texttrack;
};
TextDetect::TextDetect() : inifile("vtr.ini")
{
if (vtrInitialize(inifile, vtrCB_thunk, static_cast<void *>(this) ) == -1)
std::cout << "Error: Failure to initialize" << std::endl;
vtrimage = new vtrImage;
}
int TextDetect::vtrTest(cv::Mat imagetest)
{
/*store image data in an image structure*/
}
void TextDetect::vtrCB(vtrTextTrack *track)
{
/*send data to command line from callback */
I've tried copying the data I need a variety of ways and nothing works (this code is a continuation from above):
//texttrack = track;
//texttrack = new vtrTextTrack (*track);
memcpy(texttrack,track,sizeof(*track));
//vtrTextTrackFree(track);
}
void TextDetect::vtrCB_thunk(vtrTextTrack *track, void *calldata)
{
static_cast<TextDetect *>(calldata)->vtrCB(track);
}
This is the member function were I want the data to be used. Texttrack is public member so I might need it outside my class as well (this code is a continuation from above):
bool TextDetect::DrawBox(cv::Mat& tobeboxed)
{
And I get the access violation error at runtime here at this line of code (this code is a continuation from above):
if (texttrack->best->ocrconf > 90)
{
/*do some more stuff*/
}
}
Hopefully I'm understanding this correctly.
It seems to me that the problem is trying to copy those vtrTextTrack structs improperly.
This:
//texttrack = track;
just copies the pointer. If the owner of the struct (probably the caller of the callback function) destroys/deletes the vtrTextTrack, then you're holding on to an invalid pointer.
This one:
memcpy(texttrack,track,sizeof(*track));
will copy all the members of the vtrTextTrack, but will not copy what's being pointed to by it's member pointers (e.g. texttrack->best). Again, if the owner destroys/deletes the track, then you're holding on to invalid pointers.
And since
//texttrack = new vtrTextTrack (*track);
didn't work, I'm guessing that vtrTextTrack doesn't provide a copy constructor.
As for a workaround, first check if your third party library provides a function to copy these structs. If that's not the case (could this be by design?), then you may have to implement one yourself. This might be hard because there might be all kinds of internals that you don't know about. If you don't need the whole vtrTextTrack, I'd say define another struct and store only the information you need. Something along the lines of
SomeType* bestCopier(SomeType* src)
{
SomeType* temp;
/* copy over struct */
return temp;
}
Foo* fooCopier(Foo* src)
{
/*...*/
}
struct myTextTrack
{
public:
myTextTrack(vtrTextTrack* src)
{
//copy over stuff
m_best = bestCopier(src->best);
m_foo = fooCopier(src->foo);
}
private:
/* the members you care about*/
SomeType* m_best;
Foo * m_foo;
}

std::string constructor corrupts pointer

I have an Entity class, which contains 3 pointers: m_rigidBody, m_entity, and m_parent. Somewhere in Entity::setModel(std::string model), it's crashing. Apparently, this is caused by bad data in m_entity. The weird thing is that I nulled it in the constructor and haven't touched it since then. I debugged it and put a watchpoint on it, and it comes up that the m_entity member is being changed in the constructor for std::string that's being called while converting a const char* into an std::string for the setModel call. I'm running on a Mac, if that helps (I think I remember some problem with std::string on the Mac). Any ideas about what's going on?
EDIT: Here's the code for GEntity:
GEntity::GEntity(GWorld* world, unsigned long int idNum) {
GEntity(world, idNum, btTransform::getIdentity());
}
GEntity::GEntity(GWorld* world, unsigned long int idNum, btTransform trans) : m_id(idNum), m_trans(trans), m_world(world) {
// Init unused properties
m_rigidBody = NULL;
m_entity = NULL; // I'm setting it here
m_parent = NULL;
// Find internal object name
std::ostringstream ss;
ss << "Entity" << idNum << "InWorld" << world;
m_name = ss.str();
// Create a scene node
m_sceneNode = m_world->m_sceneMgr->getRootSceneNode()->createChildSceneNode(m_name+"Node");
// Initialize the SceneNode's transformation
m_sceneNode->setPosition(bv3toOv3(m_trans.getOrigin()));
m_sceneNode->setOrientation(bqToOq(m_trans.getRotation()));
}
void GEntity::setModel(std::string model) {
m_model = model;
// Delete entity on model change
if(m_entity != NULL) { // And by the time this line comes around, it's corrupt
m_world->m_sceneMgr->destroyEntity(m_entity);
m_entity = NULL;
}
// Create new entity with given model
m_entity = m_world->m_sceneMgr->createEntity(m_name+"Ent", model);
// Apply a new rigid body if needed
if(m_rigidBody != NULL) {
initPhysics();
}
}
void GEntity::initPhysics() {
deinitPhysics();
}
void GEntity::deinitPhysics() {
if(m_rigidBody != NULL) {
m_world->m_dynWorld->removeRigidBody(m_rigidBody);
delete m_rigidBody;
m_rigidBody = NULL;
}
}
And here's the definition of GEntity:
class GEntity : public btMotionState {
public:
GEntity(GWorld* world, unsigned long int idNum);
GEntity(GWorld* world, unsigned long int idNum, btTransform trans);
void setModel(std::string modelName);
void initPhysics();
void deinitPhysics();
void getWorldTransform(btTransform& worldTrans) const;
void setWorldTransform(const btTransform &trans);
void parent(GEntity* parent);
protected:
unsigned long int m_id;
// Physics representation
btTransform m_trans;
btRigidBody* m_rigidBody;
// Graphics representation
Ogre::SceneNode* m_sceneNode;
Ogre::Entity* m_entity;
// Engine representation
GWorld* m_world;
GEntity* m_parent;
std::string m_name;
std::string m_model; // Used to find physics collision mesh
};
And here's the code calling setModel:
// Setup game world
GWorld* world = new GWorld(win);
GEntity* ent = world->createEntity();
ent->setModel(std::string("Cube.mesh"));
Your problem is that this line is constructing a nameless temporary GEntity inside the constructor body for a different GEntity. The temporary is then thrown away once the statement completes and no further initialization of the non-temporary GEntity is performed.
GEntity(world, idNum, btTransform::getIdentity());
If you want to share some initialization code between your two constructors you should create a member function that performs the required actions and call this function from both constructors. C++ doesn't (currently) allow you to delegate initialization from one constructor to a different constructor or call two constructors on the same object.
My best guess is that the problem is in GWorld::createEntity. If you're creating a local GEntity on the stack and returning a pointer to it, you'll see something like what you describe, as the GEntity is destroyed when GWorld::createEntity returns and the memory is reused for the temp string constructed to pass to setModel
Edit
I see you've added more code, including the definition of createEntity. That looks fine, but I would still suggest looking for some way in which the GEntity you're seeing the problem with gets deleted (and the memory reused for a string) before you call setModel.
One solution I have found is to use string.resize(n), which will resize the function. However, I do not know why this works, and I feel my problem is with my code since std::string is part of the standard C++ library.
I can't find the answer but I can make a suggestion that will help catch the problem:
Add assertions. A lot of assertions. Each one of those functions really need some assertions at least at their beginning. That will certainly help you catch wrong states early.
And by the way, you should use a constant reference as parameter of your setModel() function.
In C++ you can not call a constructor from within a constructor.
Try
GEntity::GEntity(GWorld* world, unsigned long int idNum) : GEntity(world, idNum, btTransform::getIdentity() {}