I'm trying to create an example of binding a boost::function to a member function that goes out of scope. It is still possible to call this function, even though the object no longer exists.
I need to prove that it is not a correct use and the app needs to fail. But the memory location still seems to be in tact, so I need a way to make it fail.
The other question asked would be: am I right? Is there something I might be missing?
class bad_object {
public:
void fct1() {cout << "Fct 1 called. String value: " << sth << endl;};
void fct2(int i) {cout << "Fct 2 with param " << i << endl;};
string sth;
};
int main()
{
bad_object b;
boost::function<void ()> f1(boost::bind( &bad_object::fct1, b ));
boost::function<void ()> f2(boost::bind( &bad_object::fct2, b, 10 ));
boost::function<void ()> f3;
{
bad_object c;
c.sth = "There once was a cottage";
f3 = boost::bind( &bad_object::fct1, c );
}
// c now goes of scope, f3 should therefore be invalid
f3();
return 0;
}
output as expected.
Fct 1 called. String value:
Fct 2 with param 10
Fct 1 called. String value: There once was a cottage
Perhaps you use weak_ptr: Live On Coliru
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
struct X
{
int foo() const
{
return 42;
}
virtual ~X() {
std::cout << "I'm stepping out here\n";
}
};
int weak_call(int (X::*ptmf)() const, boost::weak_ptr<X> const& wp)
{
auto locked = wp.lock();
if (!locked)
throw boost::bad_weak_ptr();
return ((*locked).*ptmf)();
}
int main()
{
boost::function<int()> bound_foo;
{
auto x = boost::make_shared<X>();
bound_foo = boost::bind(weak_call, &X::foo, boost::weak_ptr<X>(x));
std::cout << "Bound foo returns: " << bound_foo() << "\n";
}
std::cout << "Bound foo returns: " << bound_foo() << "\n";
}
Prints:
Bound foo returns: 42
I'm stepping out here
terminate called after throwing an instance of 'boost::bad_weak_ptr'
what(): tr1::bad_weak_ptr
A more generalized version (that allows n-ary member function, optionally const-qualified) is here (requiring c++11): coliru
Related
UPDATE
It seems that the original question is not that clear, so I made another example to specify what I need.
#define RPC_FUNC(X) &X,??? // I don't know how...
class Test {
public:
static void func(int a) {}
};
int main()
{
const auto ptr1 = std::make_pair(&Test::func, "Test::func");
// const auto ptr2 = std::make_pair(RPC_FUNC(Test::func));
// ptr2.first(123); // this should call the function Test::func
// std::cout << ptr2.second; // this should print the string "Test::func"
return 0;
}
How to define the macro RPC_FUNC to make this code work? Meaning that I want to make ptr1 and ptr2 exactly the same.
ORIGINAL
I want to do a piece of code like this:
template<typename F> // F is the type of some functions
void func(F f, const std::string& funcMark) {
// do something
}
I want to pass a non-static member function and a string into the function func.
Sometimes, the second parameter is just the name of the first one. Let's see an example:
namespace sp {
class Test {
public:
void doJob() {}
};
}
func(&sp::Test::doJob, "doJob");
What I'm trying to do is to do the call above like this: func(MY_MARCO(sp::Test::doJob)).
Meaning that, the macro MY_MACRO should do expand its parameter sp::Test::doJob into &sp::Test::doJob, "doJob".
The specification what the macro should precisely do is dim. The stringizing operator # can turn macro argument into string literal:
// example code what it does
#include <iostream>
#define YOUR_MACRO(X) X() << " from " << #X "()"
int foo() { return 42; }
int main() { std::cout << YOUR_MACRO(foo) << std::endl; }
That outputs
42 from foo()
Turning string literal into std::string is also trivial:
#include <iostream>
#include <string>
#define YOUR_MACRO(X) X() << " from " << std::string(#X "()")
int foo() { return 42; }
int main() { std::cout << YOUR_MACRO(foo) << std::endl; }
Works same. So where are you stuck?
UPDATE:
Specification is now lot better! But ... it
is basically same what I already posted that you should use stringizing operator # in macro:
#include <iostream>
#define RPC_FUNC(X) &X, #X
class Test {
public:
static void func(int a) {
std::cout << "called Test::func(" << a << ")" << std::endl;
}
};
int main() {
const auto ptr1 = std::make_pair(&Test::func, "Test::func"); // gets warning about unused variable
const auto ptr2 = std::make_pair(RPC_FUNC(Test::func));
ptr2.first(123); // prints "called Test::func(123)"
std::cout << ptr2.second << std::endl; // prints "Test::func"
return 0;
}
I have this example code:
// Copyright 2019 Google LLC.
// SPDX-License-Identifier: Apache-2.0
#include <functional>
#include <iostream>
#include <string>
void f(std::function<const std::string&()> fn) {
std::cout << "in f" << std::endl;
std::cout << "str: " << fn() << std::endl;
}
int main() {
std::string str = "a";
auto fn1 = [&]() { return str; };
auto fn2 = [&]() { const std::string& str2 = str; return str2; };
auto fn3 = [&]() -> const std::string& { return str; };
std::cout << "in main" << std::endl;
std::cout << "fn1: " << fn1() << std::endl;
std::cout << "fn2: " << fn2() << std::endl;
std::cout << "fn3: " << fn3() << std::endl;
f(fn1); // Segfaults
f(fn2); // Also segfaults
f(fn3); // Actually works
return 0;
}
When I first wrote this I expected that calling fn1() inside f() would properly return a reference to the str in main. Given that str is allocated until after f() returns, this looked fine to me. But what actually happens is that trying to access the return of fn1() inside f() segfaults.
The same thing happens with fn2(), but what is surprising is that fn3() works properly.
Given that fn3() works and fn1() doesn't, is there something I'm missing about how C++ deduces the return values of lambda functions? How would that create this segfault?
For the record, here are the outputs if I run this code:
calling only f(fn3):
in main
fn1: a
fn2: a
fn3: a
in f
str: a
calling only f(fn2):
in main
fn1: a
fn2: a
fn3: a
in f
Segmentation fault (core dumped)
calling only f(fn1):
in main
fn1: a
fn2: a
fn3: a
in f
Segmentation fault (core dumped)
A lambda without trailing return type as in:
[&](){return str;};
Is equivalent to:
[&]()->auto{return str;};
So this lambda returns a copy of str.
Calling the std::function object will result in this equivalent code:
const string& std_function_call_operator(){
// functor = [&]->auto{return str;};
return functor();
}
When this function is called, str is copied inside a temporary, the reference is bound to this temporary and then the temporary is destroyed. So you get the famous dangling reference. This is a very classical scenario.
The return type deduction of lambda is changed N3638. and now the return type of a lambda uses the auto return type deduction rules, which strips the referenceness.
Hence, [&]() { return str;}; returns string. As a result, in void f(std::function<const std::string&()> fn) calling fn() returns a dangling reference. Binding a reference to a temporary extends the lifetime of the temporary, but in this case the binding happened deep inside std::function's machinery, so by the time f() returns, the temporary is gone already.
lambda deduction rule
auto and lambda return types use slightly different rules for
determining the result type from an expression. auto uses the rules in
17.9.2.1 [temp.deduct.call], which explicitly drops top-level cv-qualification in all cases, while the lambda return type is based
on the lvalue-to-rvalue conversion, which drops cv-qualification only
for non-class types. As a result:
struct A { };
const A f();
auto a = f(); // decltype(a) is A
auto b = []{ return f(); }; // decltype(b()) is const A This seems like an unnecessary inconsistency.
John Spicer:
The difference is intentional; auto is intended only to give a const
type if you explicitly ask for it, while the lambda return type should
generally be the type of the expression.
Daniel Krügler:
Another inconsistency: with auto, use of a braced-init-list can deduce
a specialization of std::initializer_list; it would be helpful if the
same could be done for a lambda return type.
Additional note, February, 2014:
EWG noted that g++ and clang differ in their treatment of this example
and referred it back to CWG for resolution.
Let's see what is deduced in your code:
fn1: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
fn2: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
fn3: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&
as you can see only the last one is actually a const&
you can check return types of your lambdas with the following code:
//https://stackoverflow.com/a/20170989/10933809
#include <functional>
#include <iostream>
#include <string>
void f(std::function<const std::string&()> fn) {
std::cout << "in f" << std::endl;
std::cout << "str: " << fn() << std::endl;
}
#include <type_traits>
#include <typeinfo>
#ifndef _MSC_VER
# include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>
template <class T>
std::string
type_name()
{
typedef typename std::remove_reference<T>::type TR;
std::unique_ptr<char, void(*)(void*)> own
(
#ifndef _MSC_VER
abi::__cxa_demangle(typeid(TR).name(), nullptr,
nullptr, nullptr),
#else
nullptr,
#endif
std::free
);
std::string r = own != nullptr ? own.get() : typeid(TR).name();
if (std::is_const<TR>::value)
r += " const";
if (std::is_volatile<TR>::value)
r += " volatile";
if (std::is_lvalue_reference<T>::value)
r += "&";
else if (std::is_rvalue_reference<T>::value)
r += "&&";
return r;
}
int main() {
std::string str = "a";
auto fn1 = [&]() { return str; };
auto fn2 = [&]() { const std::string& str2 = str; return str2; };
auto fn3 = [&]() -> const std::string& { return str; };
std::cout << "in main" << std::endl;
std::cout << "fn1: " << fn1() << std::endl;
std::cout << "fn2: " << fn2() << std::endl;
std::cout << "fn3: " << fn3() << std::endl;
auto f1=fn1();
std::cout << "fn1: " << type_name<decltype(fn1())>() << std::endl;
std::cout << "fn2: " << type_name<decltype(fn2())>() << std::endl;
std::cout << "fn3: " << type_name<decltype(fn3())>() << std::endl;
f(fn1); // Segfaults
f(fn2); // Also segfaults
f(fn3); // Actually works
return 0;
}
Say we have a class Foo defined as follows:
// foo.hpp
class Foo;
using FooCallback = std::function<void(std::shared_ptr<Foo> ins)>;
class Foo : public std::enable_shared_from_this<Foo>{
public:
Foo(int b, const FooCallback& callback):m_bar(b),
m_callback(callback){}
int
getBar();
void
doSth();
private:
int m_bar;
const FooCallback& m_callback;
};
Why will the following code cause segment fault?
// foo.cpp
#include "foo.hpp"
int
Foo::getBar(){
return m_bar;
}
void
Foo::doSth(){
std::cout << "Start ... " << std::endl;
this->m_callback(shared_from_this());
std::cout << "End ... " << std::endl;
}
int main()
{
auto f = std::make_shared<Foo>(100,
[](std::shared_ptr<Foo> ins){
std::cout << "bar: " << ins->getBar() << std::endl;
});
f->doSth();
return 0;
}
The output is:
Start ...
segmentation fault
To my understanding, this is what is going on:
In main(), f is a shared_ptr pointing to an instance of Foo, say it's ins.
When f->doSth() is called, ins.doSth() is actually called.
In ins.doSth, this is a pointer to ins. And shared_from_this() is a shared_ptr to ins.
So why is step 3 causing the segment fault?
This has nothing to do with shared_from_this. If you look in the debugger, it shows that this segfaults at the location where the std::function's internal pointer points to.
And this happens because m_callback is a reference, and the function object that it refers doesn't exist anymore when you call doSth (because it was a temporary object).
To fix this you can save m_callback by value:
const FooCallback m_callback;
Or even better, since the lambda doesn't capture anything, you could make m_callback a plain function reference (or pointer):
using FooCallback = void(std::shared_ptr<Foo> ins);
…
FooCallback& m_callback;
…
auto f = std::make_shared<Foo>(100,
*[](std::shared_ptr<Foo> ins){
std::cout << "bar: " << ins->getBar() << std::endl;
});
Please refer the following code snippet. I want to use the std::bind for overloaded function foobar. It calls only the method with no arguments.
#include <functional>
#include <iostream>
class Client
{
public :
void foobar(){std::cout << "no argument" << std::endl;}
void foobar(int){std::cout << "int argument" << std::endl;}
void foobar(double){std::cout << "double argument" << std::endl;}
};
int main()
{
Client cl;
//! This works
auto a1 = std::bind(static_cast<void(Client::*)(void)>(&Client::foobar),cl);
a1();
//! This does not
auto a2= [&](int)
{
std::bind(static_cast<void(Client::*)(int)>(&Client::foobar),cl);
};
a2(5);
return 0;
}
You need to use placeholders for the unbound arguments:
auto a2 = std::bind(static_cast<void(Client::*)(int)>(&Client::foobar), cl,
std::placeholders::_1);
a2(5);
You can also perform the binding with a lambda capture (note that this is binds cl by reference, not by value):
auto a2 = [&](int i) { cl.foobar(i); };
Consider following example.
#include <iostream>
#include <algorithm>
#include <vector>
#include <boost/bind.hpp>
void
func(int e, int x) {
std::cerr << "x is " << x << std::endl;
std::cerr << "e is " << e << std::endl;
}
struct foo {
std::vector<int> v;
void calc(int x) {
std::for_each(v.begin(), v.end(),
boost::bind(func, _1, x));
}
void func2(int e, int x) {
std::cerr << "x is " << x << std::endl;
std::cerr << "e is " << e << std::endl;
}
};
int
main()
{
foo f;
f.v.push_back(1);
f.v.push_back(2);
f.v.push_back(3);
f.v.push_back(4);
f.calc(1);
return 0;
}
All works fine if I use func() function. But in real life application I have to use class member function, i.e. foo::func2() in this example. How can I do this with boost::bind ?
You were really, really close:
void calc(int x) {
std::for_each(v.begin(), v.end(),
boost::bind(&foo::func2, this, _1, x));
}
EDIT: oops, so was I. heh.
Although, on reflection, there is nothing really wrong with your first working example. You should really favour free functions over member functions where possible - you can see the increased simplicity in your version.
While using boost::bind for binding class member functions, the second argument must supply the object context. So your code will work when the second argument is this