Using QtConcurrent::MappedReduce in a class - c++

I am currently learning QtConncurrenct for multi threaded applications. So for testing purposes I decided to implement a simple program that sums integers in a list, here is the code:
#include <QCoreApplication>
#include <QtConcurrent>
#include <functional>
class intObj{
int m_value;
public:
intObj(int val = 0):m_value(val){}
int val() const {return m_value;}
};
static intObj mapFunction(const intObj &num){
return intObj(num.val());
}
static void reduceFunction(intObj &sum, const intObj &term){
int x = sum.val();
int y = term.val();
sum = intObj(x+y);
}
class myTest{
public:
int getSum(QList<intObj> numbers);
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<intObj> n;
for(int i = 0; i < 1000 ; i++){
n.append(intObj(i));
}
myTest m;
int sum = m.getSum(n);
return a.exec();
}
int myTest::getSum(QList<intObj> numbers){
auto sum = QtConcurrent::mappedReduced(numbers,mapFunction,reduceFunction);
return sum.result().val();
}
This program now runs correctly but the map and reduce functions are outside the class. How can I modify this program such that map and reduce functions are in class intObj?
I would really appreciate a working example. Thanks in advance.

You cannot pass pointer to method to mappedReduced like that.
If you don't need the object inside the MapFunction and ReduceFunction, you should make the two functions static:
static int mappedFunction(const int num){
return num;
}
static void reduce(int &sum, const int term){
sum += term;
}
If you need to use the object, you could use std::bind (see using bound function arguments):
auto sum = QtConcurrent::mappedReduced(numbers,
std::bind(&myTest::mappedFunction, this, std::placeholders::_1),
std::bind(&myTest::reduce, this, std::placeholders::_1, std::placeholders::_2));
// Or lambda if Qt support them:
auto sum = QtConcurrent::mappedReduced(numbers,
[this] (int num) { mappedFunction(num); },
[this] (int &sum, int num) { reduce(sum, num); });
You could also use Function Objects and store a reference to your current myTest instance.

After a little more digging and rereading the Qtconcurrency on using member functions
I realised that there are 2 major points
The class of the container and the member functions SHOULD be the same
In order to avoid head aches with passing this parameter, make the member functions static
Here is the final working version
#include <QCoreApplication>
#include <QtConcurrent>
#include <functional>
class intObj{
int m_value;
public:
intObj(int val = 0):m_value(val){}
int val() const {return m_value;}
static intObj mapFunction(const intObj &num){
return intObj(num.val());
}
static void reduceFunction(intObj &sum, const intObj &term){
int x = sum.val();
int y = term.val();
sum = intObj(x+y);
}
};
class myTest{
public:
int getSum(QList<intObj> numbers);
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<intObj> n;
for(int i = 0; i < 1000 ; i++){
n.append(intObj(i));
}
myTest m;
int sum = m.getSum(n);
return a.exec();
}
int myTest::getSum(QList<intObj> numbers){
auto sum = QtConcurrent::mappedReduced(numbers,&intObj::mapFunction,&intObj::reduceFunction);
return sum.result().val();
}
Any suggestions on how to improve this program are most welcome.

Related

What is the best way for deleting dynamic allocated memory of class member

The following code is just a raw example reference. Everything works fine, but when the program is about to close it stuck for about a few seconds. It's all because of the wrong way of deleting memory I am assuming.
Please find below code snippet:
class Test {
private:
static int count;
static Test* arr;
public:
int num;
Test() {}
Test(int val) : num(val) {
arr[count] = *this;
count++;
}
~Test() {
delete[] arr;
}
void print() {
for (int a = 0; a <= count - 1; a++) {
std::cout << arr[a].num << std::endl;
}
}
};
int Test::count = 0;
Test* Test::arr = new Test[2];
int main(int argc, char** argv) {
Test t1(10);
Test t2(20);
t2.print();
return 0;
}
Don't use raw new and delete at all:
class Test {
private:
static int count;
static std::vector<Test> arr;
public:
int num;
Test() {}
Test(int val) : num(val) {
arr[count] = *this;
count++;
}
// No user-defined destructor needed!
void print() {
for (int a = 0; a <= count - 1; a++) {
std::cout << arr[a].num << std::endl;
}
}
};
int Test::count = 0;
std::vector<Test> Test::arr{2};
int main(int argc, char** argv) {
Test t1(10);
Test t2(20);
t2.print();
return 0;
}
(requires #include<vector>)
This does the same thing, but does not cause you any trouble with finding the correct place to delete. std::vector manages that for you.
Note however that whatever the purpose of this class is, it probably should not be limited in the number of Test it can create:
class Test {
private:
static std::vector<Test> arr;
public:
int num;
Test() {}
Test(int val) : num(val) {
arr.push_back(*this); // Add new element!
}
// No user-defined destructor needed!
void print() {
for (int a = 0; a < arr.size(); a++) {
std::cout << arr[a].num << std::endl;
}
}
};
int Test::count = 0;
std::vector<Test> Test::arr; // Start empty!
int main(int argc, char** argv) {
Test t1(10);
Test t2(20);
t2.print();
return 0;
}
Now you aren't limited to using only two elements and you don't have to keep track of count either!
If you want to use new (which you shouldn't), then you need to call delete[] exactly once for each new[].
In your code you call new[] once to initialize arr at program startup. You call delete[] each time a Test is destroyed and you have four Test instances in your program: 2 variables of type Test in main and 2 objects of type Test in the array that you allocate for arr. That means you are deleting the array pointed to by arr four times! That causes undefined behavior.
To do it correctly, you need to deallocate it once, when it is not needed anymore:
class Test {
private:
static int count;
static Test* arr;
public:
int num;
Test() {}
Test(int val) : num(val) {
arr[count] = *this;
count++;
}
// No user-defined destructor needed!
void print() {
for (int a = 0; a <= count - 1; a++) {
std::cout << arr[a].num << std::endl;
}
}
};
int Test::count = 0;
Test* Test::arr = new Test[2]; // Executed once at startup
int main(int argc, char** argv) {
Test t1(10);
Test t2(20);
t2.print();
delete[] arr; // We don't need the array anymore, so `delete[]` it *once*
return 0;
}
Please also note that I doubt the you are approaching whatever problem you actually have the correct way with the design of this class. If your intention is to register all objects of type Test that are created in a global registry, then you should be warned that you are saving copies of the Test objects in arr.
Discussing other approaches to such a problem is out-of-scope of the question, especially if I don't know the actual intended use. So I will stop here.
You are deleting the static memory in arr multiple times which leads to undefined behavior.

How to create delegate function in QT

In C# we declare delegate function of a class like this:
public delegate void MyClassDelegate(float num);
And then we can use it on other functions like this:
public int SomeFunction(float num, MyClass.MyClassDelegate del);
How do I do this or something like this on QT?
It's not related to Qt. Use std::function for that:
void caller(int value, std::function<float(int)> delegate)
{
qDebug() << delegate(value);
}
float divide(int value)
{
return float(value) / 3;
}
int main(int argc, char *argv[])
{
caller(7, divide);
return 0;
}
If you need something elaborate (such as storing a state to create a proxy function, etc.), you can also use an object with a () operator:
struct MyDelegate
{
float operator()(int value) { return float(value) / 3; }
};
float divide(int value)
{
return float(value) / 3;
}
void caller(int value, MyDelegate& delegate)
{
qDebug() << delegate(value);
}
int main(int argc, char *argv[])
{
MyDelegate delegate;
caller(7, delegate);
return 0;
}

Value to index in Q_ENUM

QMetaEnum contains method to convert enum index to actual value:
int value(int index) const
But how to convert back to index, for example, if I want to use enum in some control where I need sequence by index?
int index(int value) const
?
Use the following function:
int indexFromValue(const QMetaEnum & e, int value){
for(int ix=0; ix< e.keyCount(); ix++){
if(e.key(ix) == e.valueToKey(value))
return ix;
}
return -1;
}
Example:
#include <QCoreApplication>
#include <QMetaEnum>
#include <QObject>
class Foo : public QObject
{
Q_OBJECT
public:
using QObject::QObject;
enum class FooEnumType { TypeA=10, TypeB=21 };
Q_ENUM(FooEnumType)
};
static int indexFromValue(const QMetaEnum & e, int value){
for(int ix=0; ix< e.keyCount(); ix++){
if(e.key(ix) == e.valueToKey(value))
return ix;
}
return -1;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const QMetaObject &mo = Foo::staticMetaObject;
int index = mo.indexOfEnumerator("FooEnumType");
QMetaEnum metaEnum = mo.enumerator(index);
Q_ASSERT(indexFromValue(metaEnum, 10) == 0);
Q_ASSERT(indexFromValue(metaEnum, 21) == 1);
Q_ASSERT(indexFromValue(metaEnum, 100) == -1);
return 0;
}
#include "main.moc"

Best way to delete job context objects in a pipelined processor

I'd appreciate it if someone suggests a way to finally delete context objects used represent a job processed through a pipeline of steps.
Here in the following code an object of class text_file_processing_request is created and sent to the io_service. My pipeline here is made up of one step, there could be more steps in real code.
Now, I would like to get opinions on the best way to delete these objects of type text_file_processing_request once they are done with.
Thank you!
#include <iostream>
#include "boost/asio.hpp"
#include "boost/thread.hpp"
using namespace std;
namespace asio = boost::asio;
typedef std::unique_ptr<asio::io_service::work> work_ptr;
typedef boost::function<void(void) > parse_and_aggregate_fun_t;
class file_processing_request{
public:
virtual void process(int num) = 0;
};
class text_file_processing_request : public file_processing_request {
public:
virtual void process(int num) {
cout << "text_file_processing_request::process " << num << endl;
}
};
class processor {
public:
processor(int threads) : thread_count(threads) {
service = new asio::io_service();
work = new work_ptr(new asio::io_service::work(*(service)));
for (int i = 0; i < this->thread_count; ++i)
workers.create_thread(boost::bind(&asio::io_service::run, service));
}
void post_task(parse_and_aggregate_fun_t job){
this->service->post(job);
}
void stop(){
this->work->reset();
}
void wait(){
this->workers.join_all();
}
private:
int thread_count;
work_ptr * work;
asio::io_service* service;
boost::thread_group workers;
};
class job_discoverer {
public:
job_discoverer(processor *p): worker(p){}
void start_producing(){
do {
file_processing_request * cPtr = new text_file_processing_request();
this->worker->post_task(boost::bind(&file_processing_request::process, cPtr, 42));
} while (0);
this->worker->stop(); // no more data to process
}
private:
processor *worker;
};
int main(int argc, char** argv) {
processor *pr = new processor(4);
job_discoverer disocverer(pr);
disocverer.start_producing();
pr->wait();
delete pr;
return 0;
}

Call map key to invoke function requiring a parameter - how to get working

Here is my code.
#include <map>
#include <string>
#include <algorithm>
class maptest {
public:
int doubler(int val) { return val * 2; }
int halver(int val) { return val / 2; }
int negativer(int val) { return val > 0 ? -val : val; }
};
int main() {
const char* const ID[] = {"doubler", "halver", "negativer" };
int ID_SIZE = sizeof(ID) / sizeof(*ID);
//signature of maths functions
typedef int (maptest::*mathfunc)(int);
mathfunc mfuncs[] = { &maptest::doubler, &maptest::halver, &maptest::negativer};
std::map<std::string, mathfunc> mathmap;
for(int i = 0; i < ID_SIZE; ++i) {
mathmap.insert(std::make_pair(ID[i], mfuncs[i]));
}
//C2064: term does not evaluate to a function taking 1 argument
int result = *mathmap["doubler"](3);
return 0;
}
I think this would work if there was no parameter to be passed to the functions. But how do I pass a parameter in this way?
Your mathfuncs are member functions, so you need an object on which to invoke them:
maptest mt;
int result = (mt.*(mathmap["doubler"]))(3);
Alternatively, you could make your member functions static:
class maptest {
public:
static int doubler(int val) { return val * 2; }
static int halver(int val) { return val / 2; }
static int negativer(int val) { return val > 0 ? -val : val; }
};
And then define mathfunc accordingly:
typedef int (*mathfunc)(int);
And this would allow you to invoke them the way you are invoking them in your original post:
typedef int (*mathfunc)(int);
Notice, that a way to make this design more flexible is to make use of std::function, which would allow you to pass any type of callable object. For instance:
typedef std::function<int(int)> mathfunc;
mathfunc mfuncs[] = {
&maptest::doubler,
&maptest::halver,
&maptest::negativer,
[] (int i) { return i * 2; } // <== A LAMBDA...
};
You are invoking non static member function.
do the following.
maptest t;
int (maptest::*tptr) (int) = mathmap["doubler"];
int result = (t.*tptr)(2);
Hope this helps.