working with C++ fuzzylite lib and ObjC in iOS (fuzzy logic)
-
26-02-2021 - |
Frage
I've wandered into the deep end of the pool here. I've made some good progress but now am just thrashing around. I'm trying to use this fuzzy logic lib in iOS: http://code.google.com/p/fuzzy-lite/
I've got it to compile - what I did was to add both the .cpp & the .h files to my project and changed the suffix on my main viewController to ".mm". I am able to run the fuzzyLite test.h file from within viewDidload (show below). It runs and the test data is displayed.
What I need to do is create a persistent instance of fuzzyLite so I can use it in my app (e.g. be able to address it and then clean up when the app unloads).
I've searched around but haven't understood the discussions/examples of including C++ code in an ObjC project. Can someone show me a way I can move forward with this - wrapping the fuzzyLite code so I can call functions and get results back? Thanks!
EDIT: I've made progress on this using the method detailed here: http://robnapier.net/blog/wrapping-c-take-2-1-486
One thing I am unclear on is memory cleanup. The dealloc function cleans up the instance of the wrapped CPP instance - but what about memory alloc'ed within the CCP instance? Seems like I need call a method to release that prior to deleting the instance.
ex: the wrapped class has some instance vars of subclasses- is my cleanup function enough to manage the memory properly?
void Bingo::cleanup(){
delete engine;
engine = NULL;
delete health;
health = NULL;
delete energy;
energy = NULL;
}
-header for the wrapped CPP class
#include "fuzzylite/FuzzyLite.h"
namespace fl {
class Bingo {
public:
FuzzyEngine* engine;
OutputLVar* health;
InputLVar* energy;
Bingo();
void Fuzz();
void setInput(float input);
};
}
from the ObjC wrapper:
- (void)dealloc
{
delete _cpp;
_cpp = NULL;
[super dealloc];
}
FuzzyLiteIOSViewController.mm
#include "FuzzyLiteIOSViewController.h"
#include "FuzzyLite.h"
#include "test.h"
#include <limits>
#include "fuzzylite/FunctionTerm.h"
//stuff not shown
- (void)viewDidLoad
{
[super viewDidLoad];
fl::Test* test = new fl::Test();
test->SimpleMamdani();
}
test.h
#ifndef FL_TEST_H
#define FL_TEST_H
namespace fl {
class Test {
public:
static void SimpleMamdani();
};
}
#endif /* FL_TEST_H */
test.cpp
#include "fuzzylite/test.h"
#include "fuzzylite/FuzzyLite.h"
#include <limits>
#include "fuzzylite/FunctionTerm.h"
namespace fl {
void Test::SimpleMamdani() {
FuzzyOperator& op = FuzzyOperator::DefaultFuzzyOperator();
FuzzyEngine engine("simple-mamdani", op);
engine.hedgeSet().add(new fl::HedgeNot);
engine.hedgeSet().add(new fl::HedgeSomewhat);
engine.hedgeSet().add(new fl::HedgeVery);
fl::InputLVar* energy = new fl::InputLVar("Energy");
energy->addTerm(new fl::ShoulderTerm("LOW", 0.25, 0.5, true));
energy->addTerm(new fl::TriangularTerm("MEDIUM", 0.25, 0.75));
energy->addTerm(new fl::ShoulderTerm("HIGH", 0.50, 0.75, false));
engine.addInputLVar(energy);
fl::OutputLVar* health = new fl::OutputLVar("Health");
health->addTerm(new fl::TriangularTerm("BAD", 0.0, 0.50));
health->addTerm(new fl::TriangularTerm("REGULAR", 0.25, 0.75));
health->addTerm(new fl::TriangularTerm("GOOD", 0.50, 1.00));
engine.addOutputLVar(health);
fl::RuleBlock* block = new fl::RuleBlock();
block->addRule(new fl::MamdaniRule("if Energy is LOW then Health is BAD", engine));
block->addRule(new fl::MamdaniRule("if Energy is MEDIUM then Health is REGULAR", engine));
block->addRule(new fl::MamdaniRule("if Energy is HIGH then Health is GOOD", engine));
engine.addRuleBlock(block);
for (fl::flScalar in = 0.0; in < 1.1; in += 0.1) {
energy->setInput(in);
engine.process();
fl::flScalar out = health->output().defuzzify();
(void)out; //Just to avoid warning when building
FL_LOG("Energy=" << in);
FL_LOG("Energy is " << energy->fuzzify(in));
FL_LOG("Health=" << out);
FL_LOG("Health is " << health->fuzzify(out));
FL_LOG("--");
}
}
Lösung
It's basically not possible to answer your question given the information provided. Your question is about the cleanup
method of the Bingo
class, but instances of Bingo (either on the stack or the heap) appear nowhere in your code excerpts. Likewise, you state that you are cleaning up a "wrapped CPP instance" but it's referenced nowhere else. It does appear that you have leaks in your Test::SimplMamdani
method -- you new
a bunch of objects there that don't [at least in the revealed code] have any corresponding delete
s. Similarly, in your FuzzyLiteIOSViewController::viewDidLoad
method you create a Test
instance on the heap without a corresponding delete
. I'm assuming that there's no autoptr stuff going on under the hood in your C++ code.
UPDATED to provide additional information:
Based upon your comment, you need to review the basic language structure of C++. The basic rule is that you'll need to delete
anything that you new
. Clean up for the Bingo
class should be performed in the destructor (a C++ construct to Objective-C's dealloc
). Your Bingo
class should look something more like:
Bingo.h:
namespace fl {
class Bingo {
public:
Bingo();
virtual ~Bingo();
void Fuzz();
void setInput(float input);
FuzzyEngine* engine;
OutputLVar* health;
InputLVar* energy;
protected:
private:
};
}
Bingo.cpp:
using namespace fl;
Bingo::Bingo() {
}
Bingo::~Bingo() {
if (engine) {
delete engine;
}
if (health) {
delete health;
}
if (energy) {
delete energy;
}
}
When you delete
a Bingo instance, the destructor will be called and Bingo
's member variables will be disposed.
Arguably your member variables (engine, health, and energy) should be private in scope and exposed via public-scoped getters and setters.
Grab a copy of Bjarne Stroustrup's C++ reference and give it a quick perusal, or use an online get-up-and-going guide like this one.