06 Jul 2017
This post is in continuation to Functors in C++ - Part I.
In last blog we talked about basics of functors. In this post let’s dive deep into functors and talk about some application of functors.
Functors are commonly used in STL algorithms. The power of functors can clearly be realised when we use them with STL.
STL Functors
There is one more good thing to this whole story. We don’t have to write all functors by ourselves. STL provides some built-in functors for basic operations like addition, divison, some bitwise operators etc.
Some of the STL Functors are^:
- Binary Arithmetic Functors : plus (for addition, equivalent to arg1 + arg2), minus (for subtraction, same as arg1 - arg2 ), divides (division) etc. ^^
- Binary Logical Functors : logical_and, logical_or
- Unary Functors : negate, logical_not.
Binary functors are functors those take two parameters while unary take only one parameter.
^ Complete list and their descriptions can be found here.
^^ arg1 and arg2 are two input parameters to functors. Example: std::plus<int>()(arg1 + arg2)
Let’s take a example here. Assume we need to multiply each element of vector by -1. This can be done very easily as:
// Compile this code with -std=c++11 flag.
// like: g++ -std=c++11 main.cpp
#include<vector>
#include<algorithm>
#include<functional>
#include<iostream>
int main(){
// Initializing vector with 1,2 and 3 as it's elements
std::vector<int> vec = {1,2,3};
// Transforming each element of vector by multiplying
// it with -1. First argument to std::Transform is
// start iterator. Second argument is end iterator
// Third argument says where we need to store the
// result. Here we are storing result in vec itself.
// And the last argument says which functor do we
// need to call for each element of vector from
// start iterator to end iterator
std::transform(vec.begin(),vec.end(),
vec.begin(),std::negate<int>());
// print the transformed vector
for(int i=0;i<vec.size();i++){
std::cout << vec[i] << ' ';
}
// output would be
// -1 -2 -3
}
It’s so easy and much more readble than doing same thing without using STL. Isn’t it!?
But we do have one problem here if we use binary functor with std::transform instead of unary functor. Binary functor takes two input arguments while std::transform expects functor with just one argument. In this scenario std::bind
can be useful.
Bind
Let’s take a example where we need to add 5 to each element of std::vector, vec1 and store the result in another vector named vec2. How can this be done using std::transform and std::plus?
Here’s the solution:
// Compile this code with -std=c++11.
// g++ -std=c++11 main.cpp
#include<vector>
#include<algorithm>
#include<functional>
#include<iostream>
#define ELEM_TO_ADD 5
int main(){
// Initializing vector with 1,2 and 3 as three elements
std::vector<int> vec1 = {1,2,3};
std::vector<int> vec2;
std::transform(vec1.begin(),vec1.end(),
std::back_inserter(vec2),
std::bind(std::plus<int>(),
std::placeholders::_1,
ELEM_TO_ADD)
);
// print the transformed vector
for(int i=0;i<vec2.size();i++){
std::cout << vec2[i] << ' ';
}
// output would be
// 6 7 8
}
Let’s try to understand logic of above piece of code. std::transform
as discussed previously invoke the functor (specified by last argument) for each element iterating from vec1.begin() to vec1.end(). Before moving forward let’s first understand what std::bind
does.
std::bind
is partial function application. What this means is suppose you have a function func1
which takes two args as func1(arg1,arg2)
.
Now, you want to define a new function func2
as:
func2(arg1){
func1(arg1,5)
}
func2
has been defined by fixing argument arg2, so func2
is said as partial application of func1
. std::bind
does same. In terms of C++ STL func2
can be defined as:
auto func2 = std::bind(func1,std::placeholders::_1,5)
What we are saying by above line is: Create func2
by binding func1, first argument of func1 (specified as, std::placeholders::_1) and 5.^
^std::placeholders::_1
means first argument, std::placeholders::_2
means second parameter and so on.
You can do more crazy things with std::bind
like changing order of arguments of a function.
Back to example
Let’s move back to our example. std::bind(std::plus<int>(),std::placeholders::_1, ELEM_TO_ADD)
in our example binds std::plus functor, first argument passed to bind (which in our case would be elements of vector, passed one by one) and constant ELEM_TO_ADD. In short this line transforms binary functor std::plus
into unary functor. Another argument of functor is fixed value ELEM_TO_ADD.
Finally, we are storing the result of functor in vector, vec2, by using stl function std::back_inserter. This function just uses push_back function of vector to insert result at back of specfied vector.
So, now you might be feeling that functors are indeed powerful. In next blog we will talk about lambdas, which are quite concise way of writing anonymous functions.
Till then Sayonara.
Exercise
Can you think of solution to re-order arguments of a functions and create a new function? Basically, we want to define func3 as
func3(arg1,arg2,arg3){
func4(arg2,arg3,arg1);
}
If yes, let me know in comments how would you achieve this using std::bind
Thanks
02 Jul 2017
What is a functor?
Functor or function object is a C++ class which defines the operator ( ). Functor let’s you create objects which “looks like” functions.
Consider below code to add two numbers:
#include<cassert>
struct MyAddFunctor {
// Constructor
MyAddFunctor(int inp){
x = inp;
}
// Defining operator()
int operator()(int y){
return x+y;
}
int x;
};
int main(){
MyAddFunctor func(5);
int ret = func(10);
//ret would be 15.
assert(ret == 15);
int ret2 = func(25);
// ret would br 30
assert(ret2 == 30);
}
Now MyAddFunctor is a functor. It is a functor because MyAddFunctor is C++ class which implemented operator().
How are functors called?
We call functors just like regular C++ class. Unlike functions we first need to create object of functor like MyAddFunctor func(5)
. We are passing 5 as argument only becase we have a constructor defined in MyAddFunctor class which takes int as an argument.
Now when object of functor class is created we invoke the function using () operator just like func(10)
.
We could also combine instantiation and invocation in single statement as MyAddFunctor(5)(10)
.
Why are they called as Function Objects?
The reason why they are called as function objects is because we can call class MyAddFunctor as if it is a function. Example : func(10)
.
Why are functors used?
The main advantage of using functor is that they store state. Consider our previous example of MyAddFunctor. In that example we stored value of x in the class and so we didn’t need to pass x in each call.
One can argue that the work done by MyAddFunctor can simply be done by writing C++ function as below:
int addFunction(int x){
return 5+x;
}
But in addFunction we are hardcoding the value 5 and in functor we are not doing so. So MyAddFunctor is more customizable.
Functors are often used in STL. We will talk about functors more in next blog post. Till then stay tuned and let me know your comments on this post.
Thanks
29 Jun 2017
Recently I encountered a performance issue in C++ code. I wrote around 200 lines of C++ code which was working perfectly fine with small input but damm slow with large input. I decided to profile the C++ code using gprofile. As a newbie to profiling market I searched a lot but was not able to find step by step instructions on how to profile C++ code line be line. And so I decided to document the steps I followed in this blog post.
There are many profilers available in market but after reading a lot about them I decide to go with gprof. To keep the post short and to the point I won’t describe logic behind each step.
Step 1. For check whether gprof is installed on your system.To do this, just run below command in terminal
grpof
If you get an error then follow below step to install it. Else, move to next step
For debian install using command
`apt-get install binutils`
For Mac Os using command (assuming you have homebrew installed)
`brew install binutils`
Step 2. Compile your C++ code with -pg -g
flag. Something like:
g++ -pg -g -o final final.cpp
15 Jun 2017
Exercise : Counting
Count upto 5 in tensorflow
Expected Output
1
2
3
4
5
Caution : Solution for exercise is below. Please try solving problem by yourself before looking below
import tensorflow as tf
# Initialize count with value 0
count = tf.Variable(0)
newVal = tf.add(count,1)
# Assign operation updates the value of ref
# https://www.tensorflow.org/api_docs/python/tf/assign
assignment = tf.assign(count,newVal)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
# Now update the count 5 times
for count in range(5):
print(sess.run(assignment))
10 Jun 2017
What is a ThreadPool
A thread pool is a pool of initialized threads which are ready to take workload. Thread pool is preferred over conventional thread system when we have large number of small task to be done.
Working
When ThreadPool class is initialized then few number of threads are created (we may even create zero threads initially, as done in my implementation) and these newly created threads are made to wait on condition variable.
Now when we want a thread from our threadpool to run a new job we follow below steps:
- Check if there is any free thread in our ThreadPool. Free thread means thread which is waiting on condition variable.
- If there is atleast one free available then choose one free thread from pool and jump to step 5. Else continue.
- Create few more threads like 5, 10 or so and make these new threads wait on condition variable too.
- Now select one free thread from newly created threadpool.
- Wake the selected thread by signalling on condition variable and give the workload to this selected thread.
- When the workload is finished then make the thread wait on condition variable again.
In threadpool we never destroy any thread until destructor of ThreadPool class is called.
API
Following methods are available in the API:
Signature |
Parameters |
Return |
Description |
ThreadPool::ThreadPool() |
None |
None |
Constructor. Creates zero threads and initializes all the required members of ThreadPool class. |
ThreadPool::~ThreadPool() |
None |
None |
Destructor. Destructs ThreadPool class. |
int ThreadPool_run(struct ThreadPool tp, struct ThreadID threadId, void* (*run)(void *), void * args) |
struct ThreadPool* : ThreadPool Id returned by ThreadPool constructor. void* (run)(void *) : Workload. Callback function which selected thread should run. void : Arguments to be passed to callback function. |
0 on Success and 1 on failure |
Workload is send to ThreadPool using this function. |
int ThreadPool_join(struct ThreadID thdid, void **ret) |
struct ThreadID : ThreadId as reutrned by ThreadPool_run. void** : Return value of callback function for a given ThreadID is returned back. |
0 on Success,and 1 on failure |
This function blocks the calling thread till ThreadId passed in argument is busy with some workload and function returns when workload is completed. In case given ThreadId is not running any workload then this function returns immediately. |
Implementation
Can be found here.
Hope you found this post useful. Please comment in case of any query.
Thanks