I use SWIG to bind C++ classes so I can use them in Lua.
I wonder if it's possible to handle construction failure of C++ class in Lua.
For example, I have the following Test class which tries to get the Userdata when it's constructed.
void *getUserdata(lua_State *L, const char *key)
{
lua_pushstring(L, key);
lua_gettable(L, LUA_REGISTRYINDEX);
return lua_touserdata(L, -1);
}
class Test
{
public:
Test(lua_State *L)
:data(static_cast<MyData *>(getUserdata(L, "my_name"))){};
void setDataNum(int num)
{
data->num = num;
}
private:
MyData *data;
};
However, if getUserdata() returns nullptr, calling setDataNum() crashes my application.
I wonder if there's any way to detect and handle the construction failure(data becoming nullptr in this case) so the class won't create in Lua.
The first step to error handling would be to check for the error. From the Lua reference manual:
void *lua_touserdata (lua_State *L, int index);
If the value at the given index is a full userdata, returns its block address. If the value is a light userdata, returns its pointer. Otherwise, returns NULL.
That means we can easily check whether the call succeeded by checking data for being NULL. Then we can act accordingly, I choose to throw an exception.
test.hpp
#pragma once
#include <stdexcept>
#include <lua.hpp>
struct MyData {
int num;
};
void *getUserdata(lua_State *L, const char *key) {
lua_pushstring(L, key);
lua_gettable(L, LUA_REGISTRYINDEX);
return lua_touserdata(L, -1);
}
class Test {
public:
Test(lua_State *L)
: data(static_cast<MyData *>(getUserdata(L, "my_name"))) {
if (data == nullptr) {
throw std::runtime_error("invalid userdata at \"my_name\"");
}
};
void setDataNum(int num) { data->num = num; }
private:
MyData *data;
};
This exception is not digestible by Lua and by default the interpreter will just crash with terminate called after throwing an instance of 'std::runtime_error'. This is not so nice and we rather want to have the exception converted to a Lua error. SWIG comes with support for that.
test.i
%module example
%{
#include "test.hpp"
%}
%include <exception.i>
%exception {
try {
$action
} catch (std::exception const &e) {
SWIG_exception(SWIG_RuntimeError, e.what());
}
}
%typemap(default) (lua_State *L) { $1 = L; }
%include "test.hpp"
Lua doesn't have exceptions and thus no try-catch blocks. Instead Lua has the concept of a protected call with pcall. This will return a flag whether the call was successful and the result of the call or an error.
local example = require("example")
local success, c = pcall(example.Test)
if (success) then
c:setDataNum(1)
else
print(c)
end
Example invocation:
$ swig -c++ -lua test.i
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 -fPIC -shared test_wrap.cxx -o example.so -llua5.2
$ lua5.2 test.lua
SWIG_RuntimeError:invalid userdata at "my_name"
Related
This question already has answers here:
Difference between -pthread and -lpthread while compiling
(3 answers)
Closed 4 years ago.
I want to make use of pthread ad hence use the -lpthread flag to compile, but here's what I get:
$ g++ -lpthread pseudo_code.cpp
/tmp/cc3mPrvt.o: In function `MyThreadClass::StartInternalThread()':
pseudo_code.cpp:(.text._ZN13MyThreadClass19StartInternalThreadEv[_ZN13MyThreadClass19StartInternalThreadEv]+0x26): undefined reference to `pthread_create'
collect2: error: ld returned 1 exit status
The code I try to compile is below:
#include <pthread.h>
#include <iostream>
#include <vector>
#define OK 0
#define ERROR -1
//-- ThreadClass
class MyThreadClass
{
public:
MyThreadClass() {/* empty */}
virtual ~MyThreadClass() {/* empty */}
/** Returns true if the thread was successfully started, false if there was an error starting the thread */
bool StartInternalThread()
{
return (pthread_create(&_thread, NULL, InternalThreadEntryFunc, this) == 0);
}
/** Will not return until the internal thread has exited. */
void WaitForInternalThreadToExit()
{
(void) pthread_join(_thread, NULL);
}
protected:
/** Implement this method in your subclass with the code you want your thread to run. */
virtual void InternalThreadEntry() = 0;
private:
static void * InternalThreadEntryFunc(void * This) {
((MyThreadClass *)This)->InternalThreadEntry(); return NULL;
}
pthread_t _thread;
};
//-- /ThreadClass
//--- DUMMY DECLARATIONS BELOW TO MAKE IT COMPILE ---//
#define LOG_NS_ERROR std::cout
class test{
public:
int get_child(std::string x){return OK;};
};
test *_global;
typedef struct test_struct{} _db_transact;
class db_transact{
public:
db_transact(int,int&,int&){};
};
int _ns;
int _log_id;
//--- DUMMY DECLARATIONS ABOVE TO MAKE IT COMPILE ---//
class db_c_hndlr : public MyThreadClass{
public:
db_c_hndlr(void);
~db_c_hndlr(void);
db_transact *db_conn_get(void);
void InternalThreadEntry(void *func);
private:
int _stop;
std::vector<db_transact*> _db_pool;
};
//---------------------------------------------------------
db_c_hndlr::db_c_hndlr(void) {
}
//---------------------------------------------------------
void db_c_hndlr::InternatThreadEntry(void *func) {
while(!stop){
std::cout << "going!" << std::endl;
sleep(1);
}
}
//---------------------------------------------------------
db_c_hndlr::~db_c_hndlr() {
int i = 0;
std::vector<db_transact*>::iterator it;
for (i=0, it = _db_pool.begin();it!=_db_pool.end();it++, i++) {
if (_db_pool[i])
if (_db_pool[i]!=NULL)
delete _db_pool[i];
}
}
//---------------------------------------------------------
db_transact *db_c_hndlr::db_conn_get(void) {
db_transact *tmp;
tmp = new db_transact(_global->get_child("db_config"), _ns, _log_id);
_db_pool.push_back(tmp);
return tmp;
}
//---------------------------------------------------------
int main(void)
{
db_transact *conn=NULL;
db_c_hndlr db;
//db = new db_c_hndlr();
conn= db.db_conn_get();
return OK;
}
Probably you need to do this:
extern "C" {
#include <pthread.h>
}
That tells the compiler that this header is for a C library, and that it should not use C++ name mangling.
You also need to use -pthread instead of -lpthread, because the pthread library is special and GCC wants to explicitly know you are trying to use threads, not simply link against libpthread.
Please try to compile with the command.
g++ pseudo_code.cpp -lpthread
It makes a difference where in the command you write this option; the
linker searches and processes libraries and object files in the order
they are specified. Thus, foo.o -lz bar.o searches library z after
file foo.o but before bar.o. If bar.o refers to functions in z, those
functions may not be loaded.
It worked for me. It seems, needs to specify the library after the source file so that symbols are searched in the library.
I'm trying to get my Arduino class to return String messages with all kind of information for logging. With lots of trial and error I manage to pass a reference to the logging function to the class, but can only get a char* but not a String, and I want to be able to send Strings making it so much easier to send back all kinds of data.
I have the first part working already.
The sketch:
#include <Test.h>
#include <string.h>
void setup() {
Serial.begin(115200);
Test t;
t.setLogging(writeLog);
writeLog("Test message!" + String(" .... "));
t.doSomething("This is useful.");
t.doSomething("This as well.\n");
t.doSomething("This is even more useful.\n");
bool b = true;
}
void loop() {
}
void writeLog (char* message) {
Serial.print("char function: ");
Serial.print(message);
}
void writeLog (String message) {
Serial.print("String function: ");
Serial.println(message);
}
The header file:
#ifndef TEST_h
#define TEST_h
class Test
{
public:
Test(); // The constructor.
void setLogging(void (*)(char*)); // Takes function setting where to log.
void doSomething(char*);
};
#endif
The class:
#include <Test.h>
typedef void (*LogFunction)(char*);
LogFunction writeLog;
Test::Test () {
}
void Test::doSomething (char* s) {
// Do something useful and log the result.
writeLog(s);
}
void Test::setLogging (void (*f)(char*) ) {
writeLog = f;
return;
}
Now what I want my class to be able to do is send information like this, as String, rather than char* (I also haven't found an easy way of converting "anything" to char* and then concatenating the two or more strings):
writeLog ("HydroMonitorECSensor::setCalibration Receiving calibration - haveCalibration = " + String(haveCalibration));
writeLog ("HydroMonitorECSensor::setCalibration calibratedSlope = " + String(calibratedSlope));
writeLog ("HydroMonitorECSensor::setPins capPos set to " + String(capPos));
Where haveCalibration is a bool (which as String becomes either "true" or "false"), calibratedSlope is a double and capPos is an int. This way I can easily and cleanly send complete lines to the logger. Works great within the main script - not from the class.
I tried simply changing the char* to String and adding #include <string.h> to the library files but it doesn't work.
In Test.cpp I then get void Test::setLogging (void (*f)(String) ) { and in Test.h void setLogging(void (*)(String)); and now I get error messages:
In file included from /home/wouter/Arduino/libraries/Test/Test.cpp:1:0:
/home/wouter/Arduino/libraries/Test/Test.h:10:29: error: expected ',' or '...' before '(' token
void setLogging(void (*)(String)); // Takes function setting where to log.
^
/home/wouter/Arduino/libraries/Test/Test.cpp:16:40: error: variable or field 'setLogging' declared void
void Test::setLogging (void (*f)(String) ) {
^
/home/wouter/Arduino/libraries/Test/Test.cpp:16:31: error: 'f' was not declared in this scope
void Test::setLogging (void (*f)(String) ) {
^
/home/wouter/Arduino/libraries/Test/Test.cpp:16:34: error: 'String' was not declared in this scope
void Test::setLogging (void (*f)(String) ) {
^
exit status 1
Error compiling for board NodeMCU 1.0 (ESP-12E Module).
Suggestions?
Additional info, maybe important: I'm using the Arduino IDE and compile for ESP8266.
You are using the Arduino-provided String class, but didn't include the Arduino.h header in your test.h header file. That causes it to not find the String class and compilation fails.
The following works:
main.cpp:
#include <Arduino.h>
#include <test.hpp>
void writeLog (char* message);
void writeLog (String message);
void setup() {
Serial.begin(115200);
Test t;
t.setLogging(writeLog);
writeLog("Test message!" + String(" .... "));
t.doSomething("This is useful.");
t.doSomething("This as well.\n");
t.doSomething("This is even more useful.\n");
bool b = true;
}
void loop() {
}
void writeLog (char* message) {
Serial.print("char function: ");
Serial.print(message);
}
void writeLog (String message) {
Serial.print("String function: ");
Serial.println(message);
}
test.hpp:
#ifndef TEST_h
#define TEST_h
#include <Arduino.h> //for "String" class
//Typdef for the log function. Takes a String, returns nothing
typedef void (*LogFunction)(String);
class Test
{
public:
Test(); // The constructor.
// void setLogging(void (*)(char*)); // Takes function setting where to log.
void setLogging(LogFunction); //use the typedef here
void doSomething(char*);
};
#endif
test.cpp:
#include <test.hpp>
LogFunction writeLog;
Test::Test () {
}
void Test::doSomething (char* s) {
// Do something useful and log the result.
writeLog(s);
}
//void Test::setLogging (void (*f)(char*) ) {
void Test::setLogging (LogFunction f) { //also use typedef here
writeLog = f;
return;
}
Among other things that may arise, the compiler tells you that it cannot resolve identifier String.
This can have several reasons: First, you write String, and not string (note the capital letter in your writing). Second, if you write string and not std::string, it cannot be resolved unless you have either declared using namespace std (which is not the preferred variant for several reasons) or using std::string. Third, class std::string is declared in header <string>, which is something different than <string.h>.
So I'd write #include <string> and use then std::string.
Using clang (3.5.1) with address sanitizer on my program using boost (1.56) I got:
boost/serialization/singleton.hpp:132:13: runtime error: reference binding to null pointer
The example is:
#include<boost/serialization/singleton.hpp>
#include <string>
#include <iostream>
class Foo{
private:
std::string bar = "Hello World";
public:
void print() const{
std::cout << bar << std::endl;
}
};
int main(){
boost::serialization::singleton<Foo> test;
test.get_const_instance().print();
}
Then I do:
compilation
clang++ -I/boost/1_56_0/gcc-4.8.2/include/ -fsanitize=address,undefined -std=c++11 test.cpp
output
./a.out:
boost/1_56_0/gcc-4.8.2/include/boost/serialization/singleton.hpp:132:13: runtime error: reference binding to null pointer of type 'const Foo'
Hello World
Looking at the code, I am confused by the role of the reference instance in the class singleton. It looks like undefined behaviour.
Do you get it?
template<class T>
bool detail::singleton_wrapper< T >::m_is_destroyed = false;
} // detail
template <class T>
class singleton : public singleton_module
{
private:
BOOST_DLLEXPORT static T & instance;
// include this to provoke instantiation at pre-execution time
static void use(T const &) {}
BOOST_DLLEXPORT static T & get_instance() {
static detail::singleton_wrapper< T > t;
// refer to instance, causing it to be instantiated (and
// initialized at startup on working compilers)
BOOST_ASSERT(! detail::singleton_wrapper< T >::m_is_destroyed);
use(instance); // That's the line 132
return static_cast<T &>(t);
}
public:
BOOST_DLLEXPORT static T & get_mutable_instance(){
BOOST_ASSERT(! is_locked());
return get_instance();
}
BOOST_DLLEXPORT static const T & get_const_instance(){
return get_instance();
}
BOOST_DLLEXPORT static bool is_destroyed(){
return detail::singleton_wrapper< T >::m_is_destroyed;
}
};
I wasn't able to get the (address?) sanitizer working in my Xcode 6 environment. But I did trace through the program with the debugger. line 132 of singleton.hpp contains the line
use(instance);
where the value of instance has the (uninitialized value of zero). This might be considered an error by the sanitizer, but use(...) is an empty function. It is only included to guarantee that the singleton is called before main. If this isn't included, compile for release may optimize away the pre-main invocation and the class may not function as intended. So I would call this an over zealous behavior of the sanitizer. Or maybe the sanitizer could be considered not smart enough to trace one more level deep. or... .
Here is a piece of code that I have my exception in:
try {
hashTable->lookup(bufDescTable[clockHand].file, bufDescTable[clockHand].pageNo, dummyFrame);
}
catch (HashNotFoundException *e) {
}
catch (HashNotFoundException &e) {
}
catch (HashNotFoundException e) {
}
catch (...) {
}
Exception is generated within hashTable->lookup like that:
throw HashNotFoundException(file->filename(), pageNo);
Here is hashTable-lookup method signature
void BufHashTbl::lookup(const File* file, const PageId pageNo, FrameId &frameNo)
Exception escalates to top level like it's nobody's business.
I am using Mac(Lion) and Xcode(g++ for compiler)
Any thoughts would be appreciated.
Thanks!
We really need a complete example / further info to diagnose this for you.
For example the following version of the code compiles and works for me, outputing HashNotFoundException &
Note the code has some minor changes from your original, but they should not be material.
However it does generate the following warning:
example.cpp: In function ‘int main()’:
example.cpp:42: warning: exception of type ‘HashNotFoundException’ will be caught
example.cpp:38: warning: by earlier handler for ‘HashNotFoundException’
I'm compiling using i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00) on OS X 10.8.5
#include <iostream>
#include <sstream>
struct BadgerDbException {};
struct PageId {};
struct FrameId {};
struct HashNotFoundException : public BadgerDbException {
std::string name;
PageId pageNo;
HashNotFoundException(const std::string& nameIn, PageId pageNoIn)
: BadgerDbException(), name(nameIn), pageNo(pageNoIn) {
}
};
struct HashTable {
void lookup(void* file, const PageId pageNo, FrameId &frameNo) {
throw HashNotFoundException("a file", pageNo);
}
};
int main() {
HashTable * hashTable = new HashTable;
PageId a_Page_ID;
FrameId dummyFrame;
try {
FrameId dummyFrame;
hashTable->lookup(NULL, a_Page_ID, dummyFrame);
}
catch (HashNotFoundException *e) { std::cout<<"HashNotFoundException *"<<std::endl;}
catch (HashNotFoundException &e) { std::cout<<"HashNotFoundException &"<<std::endl;}
catch (HashNotFoundException e) { std::cout<<"HashNotFoundException"<<std::endl; }
catch (...) { std::cout<<"... exception"<<std::endl; }
}
I am a real C++ noob, so please be patient with me. First lets set the stage.
I have a C++ source in binary.cpp that compiles to a binary which looks like:
# include "lotsofheaders.h"
int main(int argc, char* argv[])
{
int errorcode = FOOBAR_GLOBAL_UNKNOWN;
// foobar instanciation
Foobar foobar();
// multiple calls to :send_auth passing in foobar instance
errorcode = send_auth(getX(), getY(), foobar);
errorcode = send_auth(getX(), getY(), foobar);
errorcode = send_auth(getX(), getY(), foobar);
return errorcode == FOOBAR_OK ? EXIT_SUCCESS : EXIT_FAILURE;
}
The send_auth method is loaded from another object code file and it gets passed an instance of foobar. The reason is, Foobar comes from an API object that I do not have the source of and which MUST NOT be instantiated more than once.
Since main is called only once, everything works as expected: There is only one instance of Foobar and send_auth can be called multiple times.
The binary is not of any use for me, I need a shared object library that does the same. It creates only one instance of Foobar and exposes an external interface method send_with_auth that can be called multiple times after my shared object lib was loaded.
My library code in library.cpp looks some like this:
# include "lotsofheaders.h"
# include "library.h"
const char* send_with_auth(const char* X, const char* Y){
std::string x(X);
std::string y(Y);
int result = send_auth(x, y, 'some Foobar singleton');
return true;
}
Since I load my shared object library via Ruby FFI I need some C-Style headers in library.h for my lib:
extern "C" {
const char* send_with_auth(const char* X, const char* Y);
}
Now with stage set I have to create an instance of Foobar exactly once inside my library and pass it into every call of send_auth to not get a memory violation error from Foobar.
Here's my (overly complex) attempt with a singleton as I understood it. There is a new library.h like so:
extern "C" {
class Singleton
{
private:
static bool instanceFlag;
static Singleton *single;
Singleton()
{
//private constructor
}
public:
static Foobar* fo;
static Singleton* getInstance();
~Singleton()
{
instanceFlag = false;
}
};
const char* send_with_auth(const char* X, const char* Y);
}
And there is this implementation library.cpp:
# include "lotsofheaders.h"
# include "library.h"
bool Singleton::instanceFlag = false;
Singleton* Singleton::single = NULL;
Singleton* Singleton::getInstance()
{
if(! instanceFlag)
{
single = new Singleton();
instanceFlag = true;
// bringing up my Foobar instance once and only once
Foobar fo;
single->fo = &fo;
return single;
}
else
{
return single;
}
}
const char* send_with_auth(const char* X, const char* Y){
std::string x(X);
std::string y(Y);
Singleton *single;
single = Singleton::getInstance();
int result = send_auth(x, y, *single->fo);
return true;
}
This code at least compiles and I can bind together everything to a shared object library. Now when I load that library in an external process (a Ruby module using Ruby FFI in my case) I always get the error:
Could not open library '/some/path/libfoobar.so': /some/path/libfoobar.so: undefined symbol: _ZN9Singleton2erE (LoadError)
I'm quite sure that my compiling/binding/stripping process from library.o to libfoobar.so is ok, because it succeeds in other cases. I am quite sure that I misunderstand C++'s singleton concept here. I wonder how I can achive my goal: create only one instance of Foobar inside my shared object library and pass it into every call of the only methods my library exposes to the outside.
Can anyone help on that?
Regards Felix
Update
Using the CommandlineParser in the library was stupid. In fact it simply returned two C-strings. The API library path and a log dir. With that I recreated a namespace:
namespace
{
char* home("/path/to/api/libs");
char* log("/tmp");
Foobar foobar(home, log);
}
That leads to a seg fault in the moment when I load the library. In contrast to that I can put these lines into my function directly:
const char* send_with_auth(const char* X, const char* Y){
std::string x(X);
std::string y(Y);
char* home("/path/to/api/libs");
char* log("/tmp");
Foobar foobar(home, log);
int result = send_auth(x, y, &foobar);
return true;
}
Everything works fine here except the fact that a second call to send_with_authlets crash everything cause Foobar is instantiated again.
Update 2:
Finally I solved it even simpler, used a globally available bool switch to initialize my Foobar instance only once:
namespace baz{
bool foobarInitialized = false;
}
const char* send_with_auth(const char* certificatePath, const char* certificatePin, const char* xmlData){
std::string certificate_path(certificatePath);
std::string certificate_pin(certificatePin);
std::string xml_data(xmlData);
Foobar *foobar_ptr;
if (! baz::foobarInitialized) {
char* home_dir("/path/to/api/lib");
char* log_dir("/tmp");
foobar_ptr = new Foobar(home_dir, log_dir);
baz::foobarInitialized = true;
}
int result = send_auth(x, y, foobar_ptr);
return xml_data.c_str();
}
Now I can call send_with_auth endlessly without having Foobar instantiated more than once. Done!
So my first suggestion is to do
The simplest thing that could possibly work
and get rid of the singleton entirely. Just create a global Foobar object in your library:
// library.cpp
namespace {
Foobar global_foobar;
}
I've put it in an anonymous namespace so it won't clash with any other symbol called "global_foobar" in the main executable, or another library.
This does mean it can only be accessed from within library.cpp. If you have more than one .cpp file linked into your lib, you'll need something marginally more elaborate:
// library_internal.h
namespace my_unique_library_namespace {
extern Foobar global_foobar;
}
// library.cpp
#include "library_internal.h"
namespace my_unique_library_namespace {
Foobar global_foobar;
}
// library_2.cpp
#include "library_internal.h"
using my_unique_library_namespace::global_foobar;