I'm creating a helper to create multiple inheritance between C++ classes and Lua objects. Because Lua store C/C++ user objects as void *, it's hard to do safe casts when you retrieve objects.
For instance,
if you have
class A { }
class B { }
class C : public A, public B { }
And you pass an object of type C to Lua, you pass the address of the C instance, when you need to cast it to B, the C++ compiler will automatically align the pointer to the position of B in C and thus, it's not safe to cast the void * pointer from C to B directly.
To avoid this issue, I use a kind of converter. In Lua, the objects contains their name as a string, so when you need to cast the object from type to an other type, it uses the converter like this:
converters["B"]["C"](mypointer, myresultpointer);
This is the class that helps creating these converters :
// Common.h
#include <functional>
#include <memory>
#include <unordered_map>
#include <string>
typedef std::function<void (void *, void *)> LuaConverter;
typedef std::unordered_map<
std::string,
std::unordered_map<
std::string,
LuaConverter
>
> LuaConverters;
class LuaeClass {
public:
static LuaConverters converters;
public:
template <class From, class To>
static void createConverter(const std::string &fromName,
const std::string &toName)
{
converters[toName][fromName] = [&] (void *ptr, void *result) -> void {
std::shared_ptr<From> *from = static_cast<std::shared_ptr<From> *>(ptr);
*((std::shared_ptr<To> *)result) = std::static_pointer_cast<To>(*from);
};
}
};
This class is compiled as static library to be used many times in the project.
Object need to be passed as shared_ptr (it also solve the problem of ownership and deletion). It works well, however, it segfaults when using as static libraries.
Then, I have a simple module Battery, compiled as shared object and links to the common library.
For the scope of the example, it does not contains much functions, but it actually use the LuaeClass:
// Battery.cpp
#include <lua.hpp>
#include "Common.h"
class Battery {
public:
int getPercent() {
return 100;
}
};
extern "C" int luaopen_battery(lua_State *L)
{
LuaeClass::createConverter<Battery, Battery>("Battery", "Battery");
return 0;
}
This compiled as a shared object named battery.so, Lua will use dlopen() and dlcose() to load it.
Finally, the main. It links to common also and use it to create objects.
// main.cpp
#include <iostream>
#include <memory>
#include <string>
#include <lua.hpp>
#include "Common.h"
using namespace std;
class LuaDeleter {
public:
void operator()(lua_State *L) {
lua_close(L);
}
};
typedef unique_ptr<lua_State, LuaDeleter> LuaState;
int main(void)
{
LuaState L(luaL_newstate());
luaL_requiref(L.get(), "_G", luaopen_base, 1);
luaL_requiref(L.get(), "package", luaopen_package, 1);
// This will dlopen() and dlclose()
string code = "local battery = require \"battery\"";
LuaeClass::createConverter<int, int>("Int", "Int");
if (luaL_dostring(L.get(), code.c_str()) != LUA_OK) {
cerr << lua_tostring(L.get(), -1) << endl;
}
return 0;
}
To summary:
Common.cpp, Common.h are compiled as simple static library (libcommon.a)
Main.cpp, compiled and links to libcommon.a
Battery.cpp, compiled as a shared object and links to libcommon.a
The main segfaults at exit, the core file says it's in the destructor of std::function<> so I guess it is called multiple times on the same pointer, is it?
Is the static library data shared in all code? How can I avoid this issue?
The begin of the core
#0 0x0000000000404062 in std::__1::function<void (void*, void*)>::~function() ()
#1 0x0000000000404025 in std::__1::function<void (void*, void*)>::~function() ()
The next trace are just unreadable and unusable.
The code and global/static data of static library will be injected into each module which links it. So for your case, there are multiple LuaeClass::converters instances exist in your project. And you need to call luaopen_battery() in each module which links the static library.
I am not sure if your crash has anything to do with static link, but I am quite sure you went to a complicated implementation.
The first issue you want to address is safely converting void* to A*, B*, C*. Which class/interface you want to export to Lua? If it's class C, you can define below methods in class C:
void pushThis(lua_State *L);
static C* getThis(lua_State *L, int idx);
Both methods use C*, so you don't need a convert function. You can use meta table to distinguish your pointers from other userdata. If you need B*, just:
B* b = (B*)C::getThis(L, idx);
And you may not really need a shared_ptr. shared_ptr doesn't help on deleting your C++ object when your Lua object is collected by GC(because the shared_ptr still exist in heap). Instead, you have to implement a __gc callback in the meta table to delete your object.
Related
I'm fairly new to C++, this is also my first post on here. I'm trying to use C++ in an embedded systems project so I can take the OOP approach. I'm using the AVR crosspack toolchain (AVR G++ compiler)
My problem is this:
From what i've read, the heap should not be used for dynamic memory allocation in embedded systems. In any case, there is no implementation for "new" in AVR G++ anyway. I'm using composition, starting with a USART driver (lets call it a service), and a logger (singleton pattern, and also a service).
It's my understanding that services should have their dependancies passed in on instantiation using constructor parameters, however when I try to compose the objects needed in this way I get the following error:
Main/main.cpp: In function 'int main()':
Main/main.cpp:21:13: error: request for member 'log' in 'logSystem', which is of non-class type 'LogSystem(Usart)'
21 | logSystem.log("Hello");
| ^~~
make: *** [Main/main.o] Error 1
My sense is that my syntax for passing in an object as a constructor parameter is wrong, but I'm not sure what it should be as all the examples i can find use the "new" keyword in the constructor definition to create the object on the free store. Can anyone help?
The Code:
In "usart.h":
#include <avr/io.h>
#include <util/setbaud.h>
class Usart
{
public:
// Constructor and destructor
Usart();
~Usart();
// Initialisation routine
static void const init(void);
// Utility function to transmit a string
static void const print(const char myString[]);
};
In "logger.h":
#include "usart.h"
class LogSystem
{
public:
LogSystem(Usart usart);
~LogSystem();
Usart usart;
static void const log(char *msg);
};
In "logger.cpp"
#include "logger.h"
LogSystem::LogSystem(Usart usart)
{
Usart usart;
usart.init();
}
LogSystem::~LogSystem()
{
}
LogSystem::log(char *msg)
{
usart.print(msg);
}
In "main.cpp":
#include "logger.h"
int main()
{
LogSystem logSystem(Usart usart);
while(1)
{
logSystem.log("Hello");
}
return 0;
}
[...] the heap should not be used for dynamic memory allocation in embedded systems.
It depends. I'm currently in an embedded project with maximum safety-related requirements, and we use new, but not delete. So we have a heap, but don't allocate "dynamically", because all allocated objects are kept during the runtime.
In any case, there is no implementation for "new" in AVR G++ anyway.
Is this true? I never checked... It might be necessary to provide a heap before being able to use new.
It's my understanding that services should have their dependancies passed in on instantiation using constructor parameters, [...]
This is a good idea. ;-) It helps unit-testing.
For your syntactical and design problems: This is how I would write your sources.
"usart.h":
All methods are non-static to have access to member variables.
The const attribute on a return type is doing nothing. Did you mean to declare the method constant? Then const belongs after the parameter list. However, this attribute might be wrong if such a method changes any member variable.
#include <avr/io.h>
#include <util/setbaud.h>
class Usart
{
public:
Usart();
~Usart();
void init(void);
void print(const char myString[]);
};
"logger.h":
Just give and store a reference to the USART to avoid a copy.
#include "usart.h"
class LogSystem
{
public:
LogSystem(Usart& usart);
~LogSystem();
void log(const char *msg);
private:
Usart& _usart;
};
"logger.cpp"
The member variable _usart is directly initialized in the constructor, before any statement is executed.
#include "logger.h"
LogSystem::LogSystem(Usart& usart) : _usart(usart)
{
_usart.init();
}
LogSystem::~LogSystem()
{
}
void LogSystem::log(const char *msg)
{
_usart.print(msg);
}
"main.cpp":
Provide the USART object on the stack, as the logger.
#include "logger.h"
int main()
{
Usart usart;
LogSystem logSystem(usart);
while(1)
{
logSystem.log("Hello");
}
return 0;
}
The singleton design pattern is deprecated since it was invented, because it is so hard to test. Simply use just one object or a limiting object factory.
In my code, I want to create a dynamic array of objects. I don't know how many objects I want until the runtime, and the array's class has a dynamic variable array, so my objects can be of any size. Therefore, to make an array of them, I want to create an array of pointers as pointers are of a fixed size. Then, during runtime, when I know how many objects I will store, I want to malloc the memory needed to store the pointers. When I try mallocing, I get a linking error unless I define the array at the top of the .cpp file, even though it's already declared in the header .h file, and I am not sure why this is necessary.
My code:
Maintest.cpp
#include <iostream>
#include "class.h"
#include "Maintest.h"
//Class** Maintest::testArray = NULL; //uncommenting this line fixes the linking error
void Maintest::createMany(){
testArray = (Class **) malloc(10 * sizeof(Class *));
}
int main(){
printf("hello");
}
Maintest.h
class Maintest {
private:
static Class** testArray;
public:
static void createMany();
};
class.cpp
#include <iostream>
#include "class.h"
Class::Class(int arg){
test = arg;
}
class.h
class Class {
private:
int test;
public:
Class::Class(int);
};
In olden times, it wasn't enough to declare a static variable in your class; you had to define it in exactly one source file. This is why uncommenting that line fixes your linker error.
But since C++17, you can get round this by declaring the variable as static inline in the class definition:
class Maintest {
private:
static inline Class** testArray;
public:
static void createMany();
};
I read through this excellent summary about dll boundaries in c++.
I wrote an example implementation in a single project.
main.cpp
#include <iostream>
#include <memory>
#include <functional>
#include "Interface.hpp"
typedef std::shared_ptr<Interface> IPTR;
int main()
{
IPTR ptr = std::shared_ptr<Interface>(MakeInterface(), std::mem_fn(&Interface::Release));
std::cout << ptr->Foo(4) << "\n";
}
Interface.hpp
#define MyAPI /*export/import*/
#define APIENTRY __stdcall
struct MyAPI Interface
{
virtual int Foo(int n) = 0;
virtual void Release() = 0;
};
extern "C" MyAPI Interface* APIENTRY MakeInterface();
Interface.cpp
#include "Interface.hpp"
struct InterfaceImpl : Interface
{
virtual int Foo(int n){ return n; }
virtual void Release(){ delete this; }
};
extern "C" MyAPI Interface* APIENTRY MakeInterface()
{
return new InterfaceImpl{};
}
My questions are
Can I move the smart pointer declaration into the header without running into C++ dll issues?
Is it correct to call delete this in the Release method?
1.) No.
extern "C" MyAPI Interface* APIENTRY MakeInterface()
{
return new InterfaceImpl{};
}
This new is used from the dll-runtime and can be incompatible with new from the executable. Destroying the object by delete (executable) may not work due to different memory managers. Rule of thumb: If you provide a create/make-function (factory) then you should provide a destroy/free/delete function. Your Release-method will work but is on a different abstraction level than MakeInterface. Rule of 2 thumbs: Export independent standard layout types in combination with pimpl.
2.) Yes.
The Method that you use is what we use at job at it works.
One thing you must pay attention is to pass only C data type of at most pod as argument of your interface.
If you didn't you may incur with memory issue.
For example if you define a function in your interface with a string argument:
struct Mapi Interface
{
void wrong(string& a_string)=0
};
you may have trouble if you compile the client and dll with a different STL version (Think a new version of dll, recompiled vith vs2015 but the client remain old, compiled with vs6).
In this example I pass a ref to string. The initial buffer of the string is allocated by the client.
Now in the dll you assign a new value to a_string, a value big enough to need reallocation.
In this way you free the initial buffer inside dll context. If the heap manager was different (different crt) you have memory issue
I'm working on a VTK program and have found a class (specifically this one: Image Region) which i need to incorporate into my code. To do so I have made a separate ImageRegion.h and ImageRegion.cpp files so they can be easily included in the project. My Problem here is the
static vtkBorderCallback *New()
function which i do not know how to implement in the .cpp file or, to be quite honest, what purpose it serves at all. What does it do? Is it even necessary to have it?
When compiling I get the error:
/home/Desktop/test/src/ImageRegion.cpp:7:10: error: ‘vtkBorderCallback::vtkBorderCallback’ names the constructor, not the type
My .h file:
//ImageRegion.h
#pragma once
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkAssemblyNode.h>
#include <vtkAssemblyPath.h>
#include <vtkBorderRepresentation.h>
#include <vtkCommand.h>
#include <vtkCoordinate.h>
#include <vtkImageMapper3D.h>
#include <vtkImageActor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkPolyData.h>
#include <vtkPropPicker.h>
#include <vtkProperty2D.h>
#include <vtkBorderWidget.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
class vtkBorderCallback : public vtkCommand
{
public:
vtkBorderCallback();
static vtkBorderCallback *New();
virtual void Execute(vtkObject *caller, unsigned long, void*);
void SetRenderer(vtkSmartPointer<vtkRenderer> ren);
void SetImageActor(vtkSmartPointer<vtkImageActor> im);
double coords[6];
private:
vtkSmartPointer<vtkRenderer> Renderer;
vtkSmartPointer<vtkImageActor> ImageActor;
};
And my .cpp file:
//ImageRegion.cpp
#include "ImageRegion.h"
vtkBorderCallback::vtkBorderCallback(){}
static vtkBorderCallback::vtkBorderCallback* New()
{
return new vtkBorderCallback;
}
void vtkBorderCallback::Execute(vtkObject *caller, unsigned long, void*)
{
//Do stuff, from original VTK example code
}
void vtkBorderCallback::SetRenderer(vtkSmartPointer<vtkRenderer> ren) {this->Renderer = ren;}
void vtkBorderCallback::SetImageActor(vtkSmartPointer<vtkImageActor> im) {this->ImageActor = im;}
Any help is much appreciated.
This
static vtkBorderCallback *New();
is a static member function called New, taking no arguments, and returning a pointer to vtkBorderCallback.
In the implementation, you should omit the static. You also need to place the function in the scope of its class:
vtkBorderCallBack* vtkBorderCallback::New()
{// ^^^^^^^^^^^^^^^^^^^
return new vtkBorderCallback; // danger! Caller needs to delete this eventually
}
In VTK nearly all of the classes derive from vtkObjectBase. They should use New() and Delete() to create and delete the objects (the constructor and destructor are protected). These methods include referencing counting to make sure that they get properly shared among other vtkObjects that may use them. There is a VTK macro (vtkStandardNewMacro) that takes care of the implementation of New() and the base class implements Delete(). So for VTK, the best way to implement the static New() method is to use that macro. For your class called vtkBorderCallBack it would look like:
vtkStandardNewMacro(vtkBorderCallBack);
This should go in your .cpp file.
To solve the error, put vtkBorderCallBack:: before New():
vtkBorderCallBack* vtkBorderCallBack::New()
~~~~~~~~~~~~~~~~~~~
{
...
}
He should not omit static since New() is meant as constructor. In this scenario I would rather expect the real constructor to be private. The implementation
static vtkBorderCallback::vtkBorderCallBack* New()
{
return new vtkBorderCallback;
}
is syntactically wrong. It has so be
vtkBorderCallBack* vtkBorderCallback::New()
{
return new vtkBorderCallback;
}
Finally the whole approach is strange. New() is not really required here, and possibly leads to a memory leak. To establish a class-specific memory management overload operators new and delete on a per-class basis. Alternatively, to prevent leaks, do not return a raw pointer; return std::auto_ptr (deprecated) or std::unique_ptr:
std::unique_ptr<vtkBorderCallBack> vtkBorderCallback::New()
{
return std::unique_ptr<vtkBorderCallBack>(new vtkBorderCallback); // uses move c'tor
}
However, std::unique_ptrs are movable but not copyable. But that's the point when leaks have to be prevented. When the pointer returned by New() is spreaded all over the code better use a std::shared_ptr.
If you have only a C++03 compiler I recommend Herb Sutter's Using auto_ptr Effectively.
Basically, I just want to be able to have a clean Lua instance made inside of my Manager class, then export the functions in the class to Lua, so that I can call functions on the already created C++ class inside of Lua.
This is the current way I am looking at solving the issue. It compiles but nothing happens in Lua.
Does anyone know what I am doing wrong, or does anyone have any other suggestions?
Manager.lua
newObject("Object", 1234)
printAll()
Manager.h
#ifndef MANAGER_H
#define MANAGER_H
#include <iostream>
#include <vector>
#include <string>
extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include "luabind/luabind.hpp"
#include "Object.h"
class Manager
{
private :
lua_State *L;
std::vector<Object> obj;
public :
Manager();
void newObject(std::string t, int nm);
void printAll();
};
#endif
Manager.cpp
#include "Manager.h"
Manager::Manager()
{
luabind::open(L);
luabind::module(L) [
luabind::class_<Manager>("Manager")
.def(luabind::constructor<>())
.def("newObject", &Manager::newObject)
];
luaL_dofile(L, "Manager.lua");
}
void Manager::newObject(std::string t, int nm)
{
if(t == "Object")
{
Object object(nm);
obj.push_back(object);
}
}
void Manager::printAll()
{
for(unsigned int i = 0; i < obj.size(); i++)
std::cout << obj[i].getNum() << std::endl;
}
so that I can call functions on the already created C++ class inside of Lua.
If you use Luabind to create a class, and then provide members of that class, then Luabind will do exactly that. It will expose a class to Lua that has members.
You cannot call a member function in C++ without an object of that class's type. And therefore, when you expose a class and its members through Luabind, you will not be able to call member functions in Lua without an object of that class's type.
Therefore, if you have some global Manager object, the proper way to expose this to Lua is to expose the object itself to Lua. Use Luabind to get the global table, then put a pointer to your Manager object in it. Alternatively, you can pass the Manager object instance as a parameter when you execute the script.
The second method would work something like this:
//Load the script as a Lua chunk.
//This pushes the chunk onto the Lua stack as a function.
int errCode = luaL_loadfile(L, "Manager.lua");
//Check for errors.
//Get the function from the top of the stack as a Luabind object.
luabind::object compiledScript(luabind::from_stack(L, -1));
//Call the function through Luabind, passing the manager as the parameter.
luabind::call_function<void>(compiledScript, this);
//The function is still on the stack from the load call. Pop it.
lua_pop(L, 1);
Your Lua script can get an instance with Lua's varargs mechanism:
local manager = ...
manager:newObject("Object", 1234)
manager:printAll()