I am trying to experiment bind in C++. Basically I have two class - Invokee. The invokee class registers a test handler that needs to be invoked upon some callbacks. The method here is -
void RegisterTestHandler(int id, TestFunction handler, std::string summary, std::string details);
Similarly, I have another method that actually invokes what has been registered -
void callHandler(int id);
Another class Test which has a function that needs to be invoked on callHandler.
unsigned int globalReset(int val);
In the main function, I am doing the nullptr for the second parameter in the bind. However, it still works and I don't get any crashes. Is it something working because of the compiler optimisation or undefined behaviour or it is something to do with bind concept.
Here is the entire experimental code.
// main.cpp
#include <iostream>
#include "test.h"
#include "invokee.h"
#include <memory>
#include <functional>
// beautify using clang-format in Vscode.
int main(int argc, char **argv)
{
auto *invokeTest = new Invokee();
Test *test = new Test();
std::string summary = "global reset summary";
std::string details = "global reset details";
//Basically there are two object from different class - InvokeTest --> does the registration of the handler.
// Now the InvokeTest has to call the member function of class object - Test.
// ?? How it can do - it can do using bind - basically, the this pointer of Test class is available to invokeTest
// therefore invokeTest can simply invoke the member function of test object.
// until the test point is valid, it can use it to invoke the method of it ?? --> Is it really correct?
delete(test); //experiment deleted the test pointer.
test= nullptr; // explicity set to nullptr
// still it works?? how come ??
invokeTest->RegisterTestHandler(1, std::bind(&Test::globalReset, test, std::placeholders::_1), summary, details);
invokeTest->callHandler(1);
return 0;
}
Here is the invokee.cpp -
#include "invokee.h"
void Invokee::RegisterTestHandler(int id, TestFunction handler, std::string summary, std::string details)
{
this->handlers[id] = handler;
this->summary[id] = summary;
this->details[id] = details;
}
void Invokee::callHandler(int id)
{
auto handler = handlers.find(id);
if (handler != handlers.end())
{
std::cout << "Found the handler --" << std::endl;
handler->second(1);
}
}
Here is the test.cpp
#include <iostream>
#include "test.h"
unsigned int Test::globalReset(int val)
{
std::cout << "global Reset invoked" << std::endl;
return 0;
}
How to pass a function as default argument to another function..
For example ...
If the question is.:
Write a program in c++ to print any message using display function and use another function namely input as default argument?
Welcome to stackoverflow. You can use std::function and give it a default, as to be seen in the print function.
#include <iostream>
#include <functional>
void foo() {
std::cout << "foo\n";
}
void bar() {
std::cout << "bar\n";
}
void print(std::function<void()> f = bar) {
f();
}
int main () {
print();
print(foo);
}
For the next question, please show what you did so far and ask from that start a concrete question.
I was reading the following post:
What changes introduced in C++14 can potentially break a program written in C++11?
and also the isocpp page:
https://isocpp.org/files/papers/p0636r0.html
So I became curious, according to the Standard: What changes introduced in C++11 can potentially break a program written in C++98?
Big one that stands out -- throwing exceptions from destructors.
In C++98 you can have programs that do this and work fine if you are careful.
In C++11 you will often have to explicitly declare the dtor noexcept(false).
Nice blog post here, on Andrzej's C++ blog.
In short, the following program used to run successfully in C++03 (under some definition of “success”):
struct S
{
~S() { throw runtime_error(""); } // bad, but acceptable
};
int main()
{
try { S s; }
catch (...) {
cerr << "exception occurred";
}
cout << "success";
}
In C++11, the same program will trigger the call to std::terminate.
Here is another case related to destructors are noexcept(true) in C++11:
// A simple program that demonstrates how C++11 and pthread_cancel don't play
// nicely together.
//
// If you build without C++11 support (g++ threadkill.cpp -lpthread), the
// application will work as expected. After 5 seconds, main() will cancel the
// thread it created and the program will successfully exit.
//
// If you build with C++11 support(g++ -std=c++11 threadkill.cpp -lpthread),
// the program will crash because the abi::__forced_unwind exception will
// escape the destructor, which is implicitly marked as noexcept(true) in
// C++11. If you mark the destructor as noexcept(false), the program does
// not crash.
#include <iostream>
#include <unistd.h>
#include <string.h>
class sleepyDestructorObject
{
public:
~sleepyDestructorObject() //noexcept(false)
{
std::cout << "sleepy destructor invoked" << std::endl;
while(true)
{
std::cout << "." << std::flush;
sleep(1);
}
}
};
void* threadFunc( void* lpParam )
{
sleepyDestructorObject sleepy;
return NULL;
}
int main(int argc, char** argv)
{
pthread_t tThreadID;
pthread_create(&tThreadID, NULL, threadFunc, NULL);
sleep(5);
pthread_cancel(tThreadID);
pthread_join(tThreadID, NULL);
return 0;
}
Original reference:
https://gcc.gnu.org/ml/gcc-help/2015-08/msg00036.html
In Visual Studio 2015, the code shown below crashes at the exit of foo(), with this error message: HEAP[NameOfExecutable.exe]: Invalid address specified to RtlValidateHeap( 00520000, 005332D4 )
Notes:
When I remove the "virtual" keyword from B::bob(), the program works perfectly fine.
The program runs correctly from a command-line (outside of Visual Studio), when compiled with "g++ -std=c++11".
Using std::move() within push_back() didn't change the output.
#include <vector>
#include <memory>
#include <iostream>
class A
{
int a;
};
class B : public A
{
int b;
virtual void bob() { };
};
void foo()
{
std::vector<std::unique_ptr<A>> test;
test.push_back(std::unique_ptr<B>(new B));
}
int main()
{
foo();
std::cout << "Reached the end\n";
std::cin.get();
}
What am I doing wrong? Thanks for any help!
If you debug the code, you'll notice that the exception arises at the exit point of foo() - when the destructor for test is called.
Both std::vector and std::unique_ptr manage their memory of course, so somewhere at this point B object that you just allocated will be destroyed.
The problem here is that you store it by an A pointer, so the A class destructor will be called.
To fix that, just introduce public virtual destructor to 'A':
class A
{
int a;
public:
virtual ~A() {}
};
need a function wrapper for std::bind that will be called before the function it's wrapper, passing the arguments along to the wrapped functions.
std::function<void (int)> foo = postbind<int>(service, handle);
That's as far as I've got too. I'd like to make the postbind object auto-deduce the type. I've tried creating an object generator make_postbind(service, handle) but it was unable to deduce the types automatically.
Below I've written a test case. Compiles using: g++ -o postbind postbind.cpp -std=c++0x -lboost_system
I'd like to get the line:
std::function<void (int)> func = postbind<int>(strand, std::bind(foo, myfoo(), 'a', _1));
Down to:
std::function<void (int)> func = postbind(strand, std::bind(foo, myfoo(), 'a', _1));
But am unsure how to. In my code, I'm starting to get some really lengthy postbind template specialisations that are beginning to eat up my horizontal whitespace :)
#include <boost/asio.hpp>
#include <thread>
#include <iostream>
#include <functional>
#include <memory>
using namespace boost::asio;
using std::shared_ptr;
typedef shared_ptr<io_service> service_ptr;
typedef shared_ptr<io_service::work> work_ptr;
typedef shared_ptr<io_service::strand> strand_ptr;
typedef std::shared_ptr<io_service::work> work_ptr;
using std::placeholders::_1;
template<typename... Args>
class postbind
{
public:
typedef std::function<void (Args...)> function;
postbind(strand_ptr strand, function memfunc)
: strand_(strand), memfunc_(memfunc)
{
}
void operator()(Args... params)
{
strand_->post(std::bind(memfunc_, std::forward<Args>(params)...));
}
private:
strand_ptr strand_;
function memfunc_;
};
// --------------------------------------------
struct myfoo
{
char a;
int b;
};
void run(service_ptr service)
{
service->run();
}
void foo(myfoo foo, char a, int x)
{
std::cout << "this thread: " << std::this_thread::get_id() << "\n"
<< x << "\n";
}
int main()
{
service_ptr service(new io_service);
strand_ptr strand(new io_service::strand(*service));
work_ptr work(new io_service::work(*service));
std::thread t(std::bind(run, service));
std::cout << "main thread: " << std::this_thread::get_id() << "\n";
std::function<void (int)> func = postbind<int>(strand, std::bind(foo, myfoo(), 'a', _1));
func(99);
t.join();
}
Thanks!
You could move your template specializations into another class so that you do not have to place them on your calls to postbind. For instance, create an empty class who's purpose is to simply hold all the long drawn-out template arguments:
template<typename... Args>
struct post_bind_traits {};
Now somewhere else in your code (i.e., another file), you could setup all the versions of arguments you would need. For instance, in a header file you could do the following:
typedef post_bind_traits<int, int> pb_int_int;
typedef post_bind_traits<double, int> pb_double_int;
//... additional definitions
Then you can create a partial template specialization of your postbind class that looks like the following:
template<typename... Args>
class postbind<post_bind_traits<Args...>> //add this partial specialization
{
public:
typedef std::function<void (Args...)> function;
postbind(strand_ptr strand, function memfunc)
: strand_(strand), memfunc_(memfunc)
{
}
void operator()(Args... params)
{
strand_->post(std::bind(memfunc_, std::forward<Args...>(params)));
}
private:
strand_ptr strand_;
function memfunc_;
};
Now you can call postbind, provided you have access to the typedef definitions in the header files, like the following:
postbind<pb_int_int>::function func = postbind<pb_int_int>(/* arguments */);
Pack all the complicated typedefs in your header, and you'll have a much cleaner code-set in your main code-module files.
I think the answer is no way. This is because of the difference between std::function and the return value of std::bind.
The function signature of std::function must be specified while being declared.
The signature of functor returned by std::bind has actually a variadic template arguments, which won't be decided until its operator() is invoked. It means that the signature is not unique at declaring time, which is definitely before evaluating time.
Look at the expected invocation, std::function<void(...)> func = postbind(strand, std::bind(foo, myfoo(), 'a', _1);. Actually, the compiler only knows the bound arguments and some placeholders. After a while, its operator() is invoked, then the unbound arguments are going to replace the placeholders, and now compiler can check whether all arguments matches the function signature or not.
If above sentences are too recondite to understand, please let me show some code:
void foo(int) {}
foo(1); // Correct.
foo(1, 2); // Illegal, signature mismatched.
auto f = std::bind(foo, _1); // Here f has no idea about unbound args for foo.
f(1); // OK, 1 matches int.
f(1, 2); // OK too, although 2 is used.
f(1, 1, 1); // Same as before ones.
auto func = postbind(
strand, std::bind(foo, _1)); // If this is acceptable,
func(99); // this is a correct invocation then.
func(99, 98); // And this should also be happy for compiler. Ambiguity!
As a result, you have to specify the signature explicitly while binding.
But anyway, here's a code snippet which might be a substitute solution I guess:
template <typename... ArgTypes>
void do_post(strand_ptr strand, ArgTypes&&... args)
{
strand->post(std::bind(std::forward<ArgTypes>(args)...));
}
int main()
{
// some code
auto original_closure = std::bind(foo, myfoo(), 'a', _1);
auto final_closure = std::bind(
do_post<decltype(std::ref(original_closure)), int>, // signature deduced here
strand, std::ref(original_closure), _1); // std::ref used for inner std::bind
final_closure(99);
// others
}