Serializing a vector of objects with FlatBuffers - c++

I have a vector of objects, let's call them Plumbuses, that I want to serialize with FlatBuffers. My schema for this example would be
namespace rpc;
struct Plumbus
{
dinglebopBatch:int;
fleeb:double;
}
table PlumbusesTable {
plumbuses:[Plumbus];
}
root_type PlumbusesTable;
since the root type can't be a vector. Calling flatc --cpp on this file generates plumbus_generated.h with functions such as CreatePlumbusesTableDirect.
The generated GeneratePlumbusesTableDirect function expects an argument const std::vector<const Plumbus *> *plumbuses. My idea was to simply take the addresses of the objects in the vector pbs and store them in another vector, pbPtrs. Since the buffer is created and sent away before pbs goes out of scope, I thought this would not be a problem.
#include <vector>
#include <iostream>
#include "plumbus_generated.h"
void send_plumbus(std::vector<rpc::Plumbus> pbs) {
std::vector<const rpc::Plumbus *> pbPtrs;
pbPtrs.push_back(&(pbs[0]));
pbPtrs.push_back(&(pbs[1]));
flatbuffers::FlatBufferBuilder buf(1024);
auto msg = CreatePlumbusesTableDirect(buf, &pbPtrs);
buf.Finish(msg);
void *msg_buf = buf.GetBufferPointer();
// here, I'd normally send the data through a socket
const rpc::PlumbusesTable *pbt = rpc::GetPlumbusesTable(msg_buf);
auto *pbPtrs_ = pbt->plumbuses();
for (const auto pbPtr_ : *pbPtrs_) {
std::cout << "dinglebopBatch = " << pbPtr_->dinglebopBatch() << ", fleeb = " << pbPtr_->fleeb() << std::endl;
}
}
int main(int argc, char** argv) {
rpc::Plumbus pb1(1, 2.0);
rpc::Plumbus pb2(3, 4.0);
std::vector<rpc::Plumbus> pbs = { pb1, pb2 };
send_plumbus(pbs);
}
Running this, instead of 1, 2.0, 3, and 4.0, I get
$ ./example
dinglebopBatch = 13466704, fleeb = 6.65344e-317
dinglebopBatch = 0, fleeb = 5.14322e-321
Why does it go wrong?

This looks like this relates to a bug that was recently fixed: https://github.com/google/flatbuffers/commit/fee9afd80b6358a63b92b6991d858604da524e2b
So either work with the most recent FlatBuffers, or use the version without Direct: CreatePlumbusesTable. Then you call CreateVectorOfStructs yourself.

Related

How to programmatically assign class/struct attributes?

I am attempting to translate my Python program to C++, but because I am new to C++ I am encountering some problems. The input file is first parsed (works, not shown) to create the INITIAL_VALUES dict/map, which I then want to use to assign the Parameters class/struct attributes using the DEST_DICT_PARAMS dict/map.
I was able to achieve this in Python code with:
import dataclasses
INITIAL_VALUES = {
"BULK": {
"MAGMA": {
"M0": 1.0,
"T0": 1320.0,
},
"ASSIM": {
"M0": 0.0,
"T0": 600.0,
},
}
}
DEST_DICT_PARAMS = {
'M0': {"MAGMA": 'Mm0', "ASSIM": 'Ma0'},
'T0': {"MAGMA": 'Tm0', "ASSIM": 'Ta0'},
}
#dataclasses.dataclass
class Parameters:
Mm0: float = None
Ma0: float = None
Ta0: float = None
Tm0: float = None
class ParametersReader:
def __init__(self):
self.parameters = Parameters()
self._assignParameters()
def _assignParameters(self):
for param_fam, dest in DEST_DICT_PARAMS.items():
for component, param in dest.items():
value = INITIAL_VALUES["BULK"][component][param_fam]
setattr(self.parameters, param, value)
params = ParametersReader()
print(params.parameters)
Output:
Parameters(Mm0=1.0, Ma0=0.0, Ta0=600.0, Tm0=1320.0)
So I wrote the corresponding C++ code:
#include <iostream>
#include <map>
using std::map;
using std::string;
map<string, map<string, map<string, float> > > INITIAL_VALUES = {{
"BULK", {
{"MAGMA", {
{"M0", 1.0},
{"T0", 1320.0},
}},
{"ASSIM", {
{"M0", 0.0},
{"T0", 600.0},
}},
}
}};
map<string, map<string, string> > DEST_DICT_PARAMS = {{
{"M0", {{"MAGMA", "Mm0"}, {"ASSIM", "Ma0"}}},
{"T0", {{"MAGMA", "Tm0"}, {"ASSIM", "Ta0"}}},
}};
struct Parameters {
float Mm0;
float Ma0;
float Ta0;
float Tm0;
} parameters;
class ParametersReader {
public:
void assignParameters_() {
map<string, map<string, string> >::iterator itr0;
map<string, string>::iterator itr1;
for (itr0 = DEST_DICT_PARAMS.begin(); itr0 != DEST_DICT_PARAMS.end(); itr0++) {
for (itr1 = itr0->second.begin(); itr1 != itr0->second.end(); itr1++) {
parameters.itr1->second = INITIAL_VALUES["BULK"][itr1->first];
}
}
}
};
int main() {
ParametersReader params;
params.assignParameters_();
}
But I'm getting an error at the line
parameters.itr1->second = INITIAL_VALUES['BULK'][itr1->first] saying "no member named 'itr1' in 'Parameters'". That error makes total sense because the code is literally trying to interpret 'itr1' as an attribute name and not the whole 'itr1->second' as the name. I think this comes down to the fact that I can't seem to find a C++ equivalent to Python's setattr(obj, name, val) function that takes an object and its attribute name and assigns it a value. Is there a C++ solution to what I am attempting?
Perhaps my entire approach is incompatible with C++. If so, would you kindly suggest an alternative approach? I would like to keep the input file format the same between the Python and C++ versions.
C++ does not have runtime reflection like Python. You cannot look up a class member by name using a runtime string because class member names do not exist at runtime.
What you can do is look up a class member via a pointer to member. This is an offset into the object calculated at compile time by the compiler:
std::map<std::string, std::map<std::string, float Parameters::*> > DEST_DICT_PARAMS = {{
{"M0", {{"MAGMA", &Parameters::Mm0}, {"ASSIM", &Parameters::Ma0}}},
{"T0", {{"MAGMA", &Parameters::Tm0}, {"ASSIM", &Parameters::Ta0}}},
}};
class ParametersReader {
public:
void assignParameters_() {
for (auto& [param_fam, dest] : DEST_DICT_PARAMS) {
for (auto& [component, param] : dest) {
parameters.*param = INITIAL_VALUES["BULK"][component][param_fam];
}
}
}
};
Demo
Note I've also used range-based for loops and structured bindings to clean up your assignParameters_ function.
C++ has no equivalent to Pythons setattr(self.parameters, param, value). If you want to have a mapping between strings and members you need to write it yourself.
You can use pointers to members to do something along the line of:
#include <map>
#include <iostream>
struct foo {
float a = 0.0f;
float b = 0.0f;
};
// list all members and their string represenation
std::map<std::string,float foo::*> mmap {
{ "a", &foo::a },
{ "b", &foo::b }
};
int main() {
foo f;
std::map<std::string,float> values {
{"a", 0.1},
{"b", 0.2}
};
for (const auto& val : values) {
// lookup the member pointers via the strings from mmap
// use the found function pointer to assing to corresponding member in f
f.*mmap[val.first] = val.second;
}
std::cout << f.a << " " << f.b << "\n";
}
Note that the code assumes that all strings present in values are also present in mmap. If not, it will fail horribly. To fix that mmap.find should be used instead and the case of not found string handleted appropriately.
This works, though there is no way to get that mapping implicitly from the class definition only. On the other, hand I can imagine libraries to exist that can help with that.

How to make the c ++ application work with the browser [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
How to make the c ++ application work with the browser. I mean a program that retrieves data from a given page (let's assume that the page displays a string) and then performs some reaction on the page. For example, the page displays a random string, and the program enters the length of the string into the form.
I am a novice programmer, so I care about information and advice on where to start. Thanks in advance for any help.
As I already promised to OP in comments, posting Partial answer, which doesn't answer all questions, but only provides handy tool to wrap (call) any Python code inside C++ program.
In my code snippet I don't even do anything with browsers, but instead show only example of computing Greatest Common Divisor using Python's standard function math.gcd().
I decided to introduce this Python-in-C++ bridge only because there exist many beautiful Python modules that work with browsers or with parsing/composing HTML, hence it is much easier to write such tools in Python instead of C++.
But expert without knowledge of default Python C API, it is not that easy to implement even simple use case - compile text of Python code, pass to it any arguments from C++, receive response arguments, return arguments back to C++. Only these simple actions need usage of a dozen of different Python C API functions. That's why I decided to show how to do it, as I know.
I implemented from scratch (specifically for OP's question) handy class PyRunner which does all the magic, usage of this class is simple:
PyRunner pyrun;
std::string code = R"(
def gcd(a, b):
import math
return math.gcd(a, b)
res = gcd(*arg)
print('GCD of', arg[0], 'and', arg[1], 'is', res, flush = True)
)";
std::cout << pyrun.Run(code, "(2 * 3 * 5, 2 * 3 * 7)") << std::endl;
std::cout << pyrun.Run(code, "(5 * 7 * 11, 5 * 7 * 13)") << std::endl;
Basically you just pass any Python code snippet to PyRunner::Run() method and also any argument (represented as Python object converted to string). Result of this call is also a returned Python object converted to string. You can also use JSON to pass any large argument as string and parse returned argument, as any JSON string is also a valid stringized Python object.
Of course you need a knowledge of Python to be able to write complex code snippets inside C++.
One drawback of my PyRunner class is that for some reason (that I didn't yet understand), you can't import Python module inside global scope, as you can see I did import math within function scope. But this is not a big deal, I think, and maybe some experts will clarify the reason.
To compile and run code you need to have pre-installed Python, and pass Python's include folder and library file as compiler arguments. For example in Windows CLang you do following:
clang.exe -std=c++20 -O3 -Id:/bin/Python39/include/ d:/bin/Python39/libs/python39.lib prog.cpp
and in Linux:
clang -std=c++20 -O3 -I/usr/include/ -lpython3.9 prog.cpp
To run the program either you should provide environment variables PYTHONHOME or PYTHONPATH or run program from Python folder (like d:/bin/Python39/) or do sys.path.append("d:/bin/Python39/") on first lines of Python code snippet embedded in C++. Without these paths Python can't find location of its standard library.
PyRunner class is thread-safe, but only single-threaded always. It means that two calls to .Run() inside two threads will be exclusively blocked by mutex. I use std::mutex instead of Python's GIL to protect from multi-threading, because it is quite alright (and faster), if you don't use Python C API in any other threads simultaneously. Also it is not allowed right now to have two instances of PyRunner objects as it does Py_Initialize() and Py_FinalizeEx() in constructor and destructor, which should be done globally only once. Hence PyRunner should be a singleton.
Below is full C++ code with implementation of PyRunner class and its usage (usage is inside main()). See console output after code below. Click Try it online! link to see compile/run of this code on free GodBolt online Linux servers.
Try it online!
#include <iostream>
#include <functional>
#include <string>
#include <string_view>
#include <stdexcept>
#include <memory>
#include <mutex>
#include <Python.h>
#define ASSERT_MSG(cond, msg) { if (!(cond)) throw std::runtime_error("Assertion (" #cond ") failed at line " + std::to_string(__LINE__) + "! Msg: '" + std::string(msg) + "'."); }
#define ASSERT(cond) ASSERT_MSG(cond, "")
#define PY_ASSERT_MSG(cond, msg) { if (!(cond) || PyErr_Occurred()) { PyErr_Print(); ASSERT_MSG(false && #cond, msg); } }
#define PY_ASSERT(cond) PY_ASSERT_MSG(cond, "")
#define LN { std::cout << "LN " << __LINE__ << std::endl << std::flush; }
class PyRunner {
private:
class PyObj {
public:
PyObj(PyObject * pobj, bool inc_ref = false) : p_(pobj) {
if (inc_ref)
Py_XINCREF(p_);
PY_ASSERT_MSG(p_, "NULL PyObject* passed!");
}
PyObject * Get() { return p_; }
~PyObj() {
Py_XDECREF(p_);
p_ = nullptr;
}
private:
PyObject * p_ = nullptr;
};
public:
PyRunner() {
Py_SetProgramName(L"prog.py");
Py_Initialize();
}
~PyRunner() {
codes_.clear();
Py_FinalizeEx();
}
std::string Run(std::string code, std::string const & arg = "None") {
std::unique_lock<std::mutex> lock(mutex_);
code = StrUnIndent(code);
if (!codes_.count(code))
codes_.insert(std::pair{code, std::make_shared<PyObj>(Py_CompileString(code.c_str(), "script.py", Py_file_input))});
PyObj & compiled = *codes_.at(code);
PyObj globals_arg_mod = PyModule_New("arg"), globals_arg = PyModule_GetDict(globals_arg_mod.Get()), locals_arg = PyDict_New(),
globals_mod = PyModule_New("__main__"), globals = PyModule_GetDict(globals_mod.Get()), locals = PyDict_New();
// py_arg = PyUnicode_FromString(arg.c_str()),
PyObj py_arg = PyRun_String(arg.c_str(), Py_eval_input, globals_arg.Get(), locals_arg.Get());
PY_ASSERT(PyDict_SetItemString(locals.Get(), "arg", py_arg.Get()) == 0);
#if 0
PyObj result = PyEval_EvalCode(compiled.Get(), globals.Get(), locals.Get());
#else
PyObj builtins(PyEval_GetBuiltins(), true), exec(PyDict_GetItemString(builtins.Get(), "exec"), true);
PyObj exec_args = PyTuple_Pack(3, compiled.Get(), globals.Get(), locals.Get());
PyObj result = PyObject_CallObject(exec.Get(), exec_args.Get());
#endif
PyObj res(PyDict_GetItemString(locals.Get(), "res"), true), res_str = PyObject_Str(res.Get());
char const * cres = nullptr;
PY_ASSERT(cres = PyUnicode_AsUTF8(res_str.Get()));
return cres;
}
private:
static std::string StrUnIndent(std::string_view const & s) {
auto lines = StrSplit(s, "\n");
size_t min_off = size_t(-1);
for (auto const & line: lines) {
if (StrTrim(line).empty())
continue;
min_off = std::min<size_t>(min_off, line.find_first_not_of("\t\n\v\f\r "));
}
ASSERT(min_off < 10000ULL);
std::string res;
for (auto const & line: lines)
res += line.substr(std::min<size_t>(min_off, line.size())) + "\n";
return res;
}
static std::string StrTrim(std::string s) {
s.erase(0, s.find_first_not_of("\t\n\v\f\r ")); // left trim
s.erase(s.find_last_not_of("\t\n\v\f\r ") + 1); // right trim
return s;
}
static std::vector<std::string> StrSplit(std::string_view const & s, std::string_view const & delim) {
std::vector<std::string> res;
size_t start = 0;
while (true) {
size_t pos = s.find(delim, start);
if (pos == std::string::npos)
pos = s.size();
res.emplace_back(s.substr(start, pos - start));
if (pos >= s.size())
break;
start = pos + delim.size();
}
return res;
}
private:
std::unordered_map<std::string, std::shared_ptr<PyObj>> codes_;
std::mutex mutex_;
};
int main() {
try {
PyRunner pyrun;
std::string code = R"(
def gcd(a, b):
import math
return math.gcd(a, b)
res = gcd(*arg)
print('GCD of', arg[0], 'and', arg[1], 'is', res, flush = True)
)";
std::cout << pyrun.Run(code, "(2 * 3 * 5, 2 * 3 * 7)") << std::endl;
std::cout << pyrun.Run(code, "(5 * 7 * 11, 5 * 7 * 13)") << std::endl;
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
Console output:
GCD of 30 and 42 is 6
6
GCD of 385 and 455 is 35
35

QLibrary functions work slow on first call

I'm using QLibrary to load functions from one .dll file.
I succesfully load it, succesfully resolve functions.
But when i use some function from that .dll for the first time, this function works very slow(even if it is very simple one). Next time i use it again - and the speed is just fine (immediately, as it should be).
What is the reason for such behaviour? I suspect some caсhing somewhere.
Edit 1: Code:
typedef int(*my_type)(char *t_id);
QLibrary my_lib("Path_to_lib.dll");
my_lib.load();
if(my_lib.isLoaded){
my_type func = (my_type)my_lib.resolve("_func_from_dll");
if(func){
char buf[50] = {0};
char buf2[50] = {0};
//Next line works slow
qint32 resultSlow = func(buf);
//Next line works fast
qint32 resultFast = func(buf2);
}
}
I wouldn't blame QLibrary: func simply takes long the first time it's invoked. I bet that you'll have identical results if you resolve its address using platform-specific code, e.g. dlopen and dlsym on Linux. QLibrary doesn't really do much besides wrapping the platform API. There's nothing specific to it that would make the first call slow.
There is some code smell of doing file I/O in constructors of presumably generic classes: do the users of the class know that the constructor may block on disk I/O and thus ideally shouldn't be invoked from the GUI thread? Qt makes the doing this task asynchronously fairly easy, so I'd at least try to be nice that way:
class MyClass {
QLibrary m_lib;
enum { my_func = 0, other_func = 1 };
QFuture<QVector<FunctionPointer>> m_functions;
my_type my_func() {
static my_type value;
if (Q_UNLIKELY(!value) && m_functions.size() > my_func)
value = reinterpret_cast<my_type>(m_functions.result().at(my_func));
return value;
}
public:
MyClass() {
m_lib.setFileName("Path_to_lib.dll");
m_functions = QtConcurrent::run{
m_lib.load();
if (m_lib.isLoaded()) {
QVector<QFunctionPointer> funs;
funs.push_back(m_lib.resolve("_func_from_dll"));
funs.push_back(m_lib.resolve("_func2_from_dll"));
return funs;
}
return QVector<QFunctionPointer>();
}
}
void use() {
if (my_func()) {
char buf1[50] = {0}, buf2[50] = {0};
QElapsedTimer timer;
timer.start();
auto result1 = my_func()(buf1);
qDebug() << "first call took" << timer.restart() << "ms";
auto result2 = my_func()(buf2);
qDebug() << "second call took" << timer.elapsed() << "ms";
}
}
};

How to handle type errors when working with blobs in SQLite?

Is there a good way to handle type errors when working with blobs in SQLite? For example, the following code registers two functions create_vector and display_vector. Basically, create_vector stores a std::vector as a blob and display_vector converts this blob into text, so that we can see it:
/* In order to use
sqlite> .load "./blob.so"
sqlite> select display_vector(create_vector());
[ 1.200000, 3.400000, 5.600000, 7.800000, 9.100000 ]
*/
#include <string>
#include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1
extern "C" {
int sqlite3_blob_init(
sqlite3 * db,
char ** err,
sqlite3_api_routines const * const api
);
}
// Cleanup handler that deletes an array
template <typename T>
void array_cleanup(void * v) {
delete [] static_cast <T *> (v);
}
// Creates and returns a std::vector as a blob
static void create_vector(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
// Create a dummy vector
auto * v = new double[5] {1.2,3.4,5.6,7.8,9.10};
// Either cleanup works
sqlite3_result_blob(context,v,sizeof(double[5]),array_cleanup <double>);
}
// Converts a std::vector into text
static void display_vector(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
// Grab the vector. Note, if this is not a vector, then sqlite will
// almost certainly segfault.
auto const * const v =static_cast <double const * const> (
sqlite3_value_blob(argv[0]));
// Assuming we have a vector, convert it into a string
auto s = std::string("[ ");
for(unsigned i=0;i<5;i++) {
// If we're not on the first element, add a comma
if(i>0) s += ", ";
// Add the number
s += std::to_string(v[i]);
}
s += " ]";
// Return the text
sqlite3_result_text(
context,sqlite3_mprintf("%s",s.c_str()),s.size(),sqlite3_free);
}
// Register our blob functions
int sqlite3_blob_init(
sqlite3 *db,
char **err,
sqlite3_api_routines const * const api
){
SQLITE_EXTENSION_INIT2(api)
// Register the create_vector function
if( int ret = sqlite3_create_function(
db, "create_vector", 0, SQLITE_ANY, 0, create_vector, 0, 0)
) {
*err=sqlite3_mprintf("Error registering create_vector: %s",
sqlite3_errmsg(db));
return ret;
}
// Register the display_vector function
if( int ret = sqlite3_create_function(
db, "display_vector", 1, SQLITE_ANY, 0, display_vector, 0, 0)
) {
*err=sqlite3_mprintf("Error registering display_vector: %s",
sqlite3_errmsg(db));
return ret;
}
// If we've made it this far, we should be ok
return SQLITE_OK;
}
We can compile this with:
$ make
g++ -g -std=c++14 blob.cpp -shared -o blob.so -fPIC
Now, if we use these functions as advertised, everything works fine:
sqlite> .load "./blob.so"
sqlite> select display_vector(create_vector());
[ 1.200000, 3.400000, 5.600000, 7.800000, 9.100000 ]
However, if we try to use display_vector on a non-vector, we segfault:
sqlite> .load "./blob.so"
sqlite> select display_vector(NULL);
Segmentation fault
Really, the issue is that the static_cast in display_vector vector is not correct. In any case, is there a good way check the type of the blob or even guarantee that we have a blob? Is there a good way to prevent a segfault when a new extension requires an input of a certain type?
A blob is just a bunch of bytes, and not every value is a blob.
Your function should check the value's type with sqlite3_value_type(), and check the length with sqlite3_value_bytes().

Issue with setting speed to DifferentialWheels in Webots C++

Small community here, but hopefully somebody sees this. I'm attempting to do a pure C++ implementation of a Webots simulation for an E-puck. The C++ documentation is sorely lacking, and I can't seem to find a resolution for this issue (the C implementation is stellar, but all the function calls were changed for C++).
Essentially, I'm just trying to get a simple application up and running...I want to make the E-puck move forward. I will post the entirety of my code below...all I'm doing is instantiating a Robot entity, printing out all the IR sensor values, and attempting to move it forward.
The issue is that it does not move. I'd think that there would be some call to link the DifferentialWheel object to the E-puck (similar to the camera = getCamera("camera") call).
If I comment out my call to setSpeed, the program works perfectly (doesn't move, but prints values). If I leave it in, the simulation freezes up after a single step, once it gets to that call. I'm not exactly sure what I'm doing wrong, to be honest.
// webots
#include <webots/Robot.hpp>
#include <webots/Camera.hpp>
#include <webots/DistanceSensor.hpp>
#include <webots/DifferentialWheels.hpp>
#include <webots/LED.hpp>
// standard
#include <iostream>
using namespace webots;
#define TIME_STEP 16
class MyRobot : public Robot
{
private:
Camera *camera;
DistanceSensor *distanceSensors[8];
LED *leds[8];
DifferentialWheels *diffWheels;
public:
MyRobot() : Robot()
{
// camera
camera = getCamera("camera");
// sensors
distanceSensors[0] = getDistanceSensor("ps0");
distanceSensors[1] = getDistanceSensor("ps1");
distanceSensors[2] = getDistanceSensor("ps2");
distanceSensors[3] = getDistanceSensor("ps3");
distanceSensors[4] = getDistanceSensor("ps4");
distanceSensors[5] = getDistanceSensor("ps5");
distanceSensors[6] = getDistanceSensor("ps6");
distanceSensors[7] = getDistanceSensor("ps7");
for (unsigned int i = 0; i < 8; ++i)
distanceSensors[i]->enable(TIME_STEP);
// leds
leds[0] = getLED("led0");
leds[1] = getLED("led1");
leds[2] = getLED("led2");
leds[3] = getLED("led3");
leds[4] = getLED("led4");
leds[5] = getLED("led5");
leds[6] = getLED("led6");
leds[7] = getLED("led7");
}
virtual ~MyRobot()
{
// cleanup
}
void run()
{
double speed[2] = {20.0, 0.0};
// main loop
while (step(TIME_STEP) != -1)
{
// read sensor values
for (unsigned int i = 0; i < 8; ++i)
std::cout << " [" << distanceSensors[i]->getValue() << "]";
std::cout << std::endl;
// process data
// send actuator commands
// this call kills the simulation
// diffWheels->setSpeed(1000, 1000);
}
}
};
int main(int argc, char* argv[])
{
MyRobot *robot = new MyRobot();
robot->run();
delete robot;
return 0;
}
Now, if this were the C implementation, I would call wb_differential_wheels_set_speed(1000, 1000); However, that call isn't available in the C++ header files.
The problem causing the freeze is due to the use of the uninitialized variable diffWheels.
DifferentialWheels (as well as Robot and Supervisor) doesn't need to be initialized.
You have to change the base class of your MyRobot class to DifferentialWheels
class MyRobot : public DifferentialWheels
and then simply call
setSpeed(1000, 1000)
and not
diffWheels->setSpeed(1000, 1000)
It doesn't seem as though you've initialized diffWheels, so I would imagine you're getting a segfault from dereferencing a garbage pointer. Try putting
diffWheels = new DifferentialWheels;
in the constructor of MyRobot.