I am trying to use a boost::function in my ReceiveRequest to run on its own thread but I must be sending the wrong parameters. (At least thats what I think the compiler is trying to tell me)
Here are the lines that is causing the issue:
//some variables for the function call
std::string something("");
asio::system_error e();
asio::thread daThread();
CurrentRequest.payload;
//attempts to call function
CurrentRequest.Callback(something, &e, CurrentRequest.payload); //line 184
CurrentRequest.Callback(something, &e, &CurrentRequest.payload); //line 185
Here is what the compiler is telling me:
g++ -o ss -pthread -lrt StringSocket.cpp main.cpp -I ~/asio/include -I ~/boost/include ~/boost/lib/*.a
StringSocket.cpp: In member function ‘void StringSocket::ProcessReceive()’:
StringSocket.cpp:184: error: no match for call to ‘(ReceiveRequest::receiveCallback) (std::string&, asio::system_error (*)(), void*&)’
/home/jsander/boost/include/boost/function/function_template.hpp:761: note: candidates are: R boost::function3<R, T1, T2, T3>::operator()(T0, T1, T2) const [with R = void, T0 = std::string*, T1 = asio::system_error&, T2 = void*]
StringSocket.cpp:185: error: no match for call to ‘(ReceiveRequest::receiveCallback) (std::string&, asio::system_error (*)(), void**)’
/home/jsander/boost/include/boost/function/function_template.hpp:761: note: candidates are: R boost::function3<R, T1, T2, T3>::operator()(T0, T1, T2) const [with R = void, T0 = std::string*, T1 = asio::system_error&, T2 = void*]
Here is the ReceiveRequest class:
class ReceiveRequest
{
typedef boost::function<void (std::string *message, asio::system_error& e, void *payload) > receiveCallback;
public:
receiveCallback Callback;
void* payload;
ReceiveRequest(receiveCallback _Callback, void* _payload)
{
Callback = _Callback;
payload = _payload;
}
~ReceiveRequest() { }
};
These errors seem to be making a distinction between pointers and references to variables. I thought they could be used interchangeable as parameters. boost::function also appears to turn all of my local variables into references.
I am also confused that one of my parameters passes as "e" turns into "asio::system_error (*)()". Why is there a second pair of parenthesis added to my variable?
There are multiple issues here:
asio::system_error e();
This isn't doing what you want. Because of the way C++ syntax works, this is actually declaring a function e that takes no parameters and returns an asio::system_error. If you add a void in the parenthesis, this becomes easier to see. It should be declared as:
asio::system_error e;
Secondly, your typedef says your function should take a reference to a system_error: asio::system_error& e. However, when you pass the above in (assuming you fix the first problem), you're trying to pass a pointer:
CurrentRequest.Callback(..., &e, ....); // Should just be 'e'
Related
Question on returning std::tie from a function. If I understand correctly, then std::tie only contains references. So, returning a std::tie which points to function-local variables is a very bad idea. Shouldn't the compiler be able to detect this and issue a warning ?
Actually, we had this error in our code and all compilers and sanitizers we have missed to detect it. I was quite puzzled that this didn't get reported by any tool. Or do I understand anything incorrectly?
#include <tuple>
struct s_t {
int a;
};
int& foo(s_t s) {
return s.a; // warning: reference to local variable 's' returned
}
int& bar(s_t &s) {
return s.a; // ok
}
auto bad(s_t s) {
return std::tie(s.a); // no warning
}
auto fine(s_t &s) {
return std::tie(s.a); // no warning
}
int main() {
s_t s1,s2;
auto bad_references = bad(s1);
auto good_references = fine(s2);
// ...
return 0;
}
Your understanding of the lifetime behavior is correct. std::tie stores only references and you must assure that they are not used after the referenced object is destroyed. By-value function parameters are destroyed either at the end of the function call or at the end of the full-expression containing the function call (implementation-defined). So using the references stored in bad_references will cause undefined behavior.
You might just be expecting too much from the compiler warning features and linter features. They generally don't do extensive analysis of the code. The analysis here would need to keep track of the reference through multiple function call layers, a store to a member and the return from the function. Such more complex analysis is what a static analyzer is for.
However, starting with version 12.1 GCC seems to use the result of inlining function calls to report with -O2 -Wall -Wextra:
In file included from <source>:1:
In constructor 'constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(const _Head&) [with long unsigned int _Idx = 0; _Head = int&]',
inlined from 'constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl(const _Head&) [with long unsigned int _Idx = 0; _Head = int&]' at /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/tuple:435:21,
inlined from 'constexpr std::tuple< <template-parameter-1-1> >::tuple(const _Elements& ...) [with bool _NotEmpty = true; typename std::enable_if<_TCC<_Dummy>::__is_implicitly_constructible<const _Elements& ...>(), bool>::type <anonymous> = true; _Elements = {int&}]' at /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/tuple:729:28,
inlined from 'constexpr std::tuple<_Elements& ...> std::tie(_Elements& ...) [with _Elements = {int}]' at /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/tuple:1745:44,
inlined from 'auto bad(s_t)' at <source>:16:24:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/tuple:193:9: warning: storing the address of local variable 's' in '*(std::_Head_base<0, int&, false>*)<return-value>.std::_Head_base<0, int&, false>::_M_head_impl' [-Wdangling-pointer=]
193 | : _M_head_impl(__h) { }
| ^~~~~~~~~~~~~~~~~
<source>: In function 'auto bad(s_t)':
<source>:15:14: note: 's' declared here
15 | auto bad(s_t s) {
| ~~~~^
<source>:15:14: note: '<unknown>' declared here
I didn't manage to get current Clang and MSVC to produce a diagnostic, though. I guess this will work for GCC also only as long as all the relevant function calls are inlined. With e.g. -O0 the GCC warning is not produced and it probably won't be produced either if there are more complex function call layers inbetween.
A static analyzer like clang-analyzer reports
<source>:16:5: warning: Address of stack memory associated with local variable 's' is still referred to by the stack variable 'bad_references' upon returning to the caller. This will be a dangling reference [clang-analyzer-core.StackAddressEscape]
return std::tie(s.a); // no warning
^
<source>:27:27: note: Calling 'bad'
auto bad_references = bad(s1);
See https://godbolt.org/z/zE8Px8vT9 for both.
With Clang trunk and optimizations disabled ASAN also reports the problem:
=================================================================
==1==ERROR: AddressSanitizer: stack-use-after-return on address 0x7fddb5e00020 at pc 0x55678be240c4 bp 0x7ffe4ed87ef0 sp 0x7ffe4ed87ee8
READ of size 4 at 0x7fddb5e00020 thread T0
#0 0x55678be240c3 in main /app/example.cpp:31:12
#1 0x7fddb849e0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x240b2) (BuildId: 9fdb74e7b217d06c93172a8243f8547f947ee6d1)
#2 0x55678bd6231d in _start (/app/output.s+0x2131d)
Address 0x7fddb5e00020 is located in stack of thread T0 at offset 32 in frame
#0 0x55678be23d2f in bad(s_t) /app/example.cpp:15
This frame has 1 object(s):
[32, 36) 's' <== Memory access at offset 32 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-return /app/example.cpp:31:12 in main
[...]
See https://godbolt.org/z/eYo7cWeaM.
Probably the inlining makes it harder for the sanitizers to detect this. They probably don't add the checks prior to inlining.
What you should know to self-answer this question is RAII (resource acquisition is initialization- Some one say it is the most importance thing needed to know in C++)
In your example:
foo(s_t s); will initialize s via copy constructor. When foo exit, s will be destroyed so that s.a referencing to a dangling object
bar(s_t &s) is ok because &s is reference to existed variable (that usually) outlive the function call
bad(s_t s) fine(s_t &s) is ok because it is return value not reference/pointer to local variable
With this following code:
#include <map>
#include <functional>
#include "main.h"
std::map<int,std::function<void()>> fnc_event_to;
void testFunction();
void initialize() {
fnc_event_to[1] = testFunction;
bool boolean = fnc_event_to[2] == testFunction;//<- error
pros::lcd::initialize();
pros::lcd::print(2,"%d",boolean);
}
I recieve this error:
invalid operands to binary expression ('std::map<int, std::function<void ()>, std::less<int>, std::allocator<std::pair<const int, std::function<void ()> > > >::mapped_type' (aka 'std::function<void ()>') and 'void (*)()')
How come I can assign the function pointer to the map but I am not able to compare it with a function pointer?
Also, if a key is not defined, what will the map return?
Is there a way to compare the std::function so I can see whether its a null function pointer or is it defined already?
Or is there a better solution for this? Originally, I'm using a while(1) loop to trap the thread and the map is just a map of what the program should do when a variable reaches the key(int). The variable is changed in a separate task so its multitasking. I couldn't use the .contains() method since I'm not using C++ 20 yet.
This is just posted for reference. Answers are quoted from #0x499602D2 and #LightnessRacesInOrbit.
Either use:
if (fnc_event_to[2]){
}
Or
if(fnc_event_to.find(2) != fnc_event_to.end()){
}
Be aware that the first option will create an empty element, so if you give the map the same value, it will already be created, and it will return true.
The standard class std::function has only these comparison operator ==
template<class R, class... ArgTypes>
bool operator==(const function<R(ArgTypes...)>&, nullptr_t) noexcept;
template<class R, class... ArgTypes>
bool operator==(nullptr_t, const function<R(ArgTypes...)>&) noexcept;
So you can only check whether an object of the class is "empty".
I am using boost v1.37 on MSVC7. I'm stuck on these old versions and cannot upgrade so please help me work within my means here and do not suggest upgrades as an answer.
I have a class with three member functions. I want to define a boost::function that can be used to call different member functions on different instances of the same class:
typedef boost::function<bool (unsigned, unsigned)> MyFunc;
The bind would look like:
boost::bind( &A::foo1, _1, _2, _3, boost::ref(some_fixed_param) );
I need to pass the boost::bind above into a function that takes a MyFunc as a parameter.
How do I need to setup my boost::function to take a function object (from boost::bind) that has the instance object set as a placeholder? How do pass the instance (this) into the boost::function? I keep getting compiler errors here so just trying to make sure I understand this properly. Hope I've explained clearly. Thanks in advance.
EDIT
The real error I get is:
sample.cpp(1156) : error C2664: 'process' : cannot convert parameter 2 from 'boost::_bi::bind_t<R,F,L>' to 'FooFunc &'
with
[
R=bool,
F=boost::_mfi::mf3<bool,A,unsigned int,unsigned int,int>,
L=boost::_bi::list4<boost::arg<1>,boost::arg<2>,boost::arg<3>,boost::reference_wrapper<int>>
]
The code I'm using:
typedef boost::function<bool (unsigned, unsigned)> FooFunc;
class A
{
public:
bool foo1( unsigned s1, unsigned s2, int s3 )
{
}
};
bool process( unsigned s1, FooFunc& foo )
{
unsigned s2 = 100;
A* a; // pretend this is valid
return foo( s1, s2 );
}
void dostuff()
{
int s3 = 300;
process( 200,
boost::bind( &A::foo1, _1, _2, _3, boost::ref( s3 ) ) );
}
Now I know this isn't valid code because in the process() function I somehow need to call foo with instance pointer a. Not sure how to connect the two and not sure why the compiler error is happening.
First of all, you would need to add a reference to your class to the signature of the boost::function:
typedef boost::function<bool (A *, unsigned, unsigned)> FooFunc;
This does require that class A be declared before this typedef. Then, in your process function, you can provide this reference when you call the given FooFunc
bool process( unsigned s1, FooFunc foo )
{
unsigned s2 = 100;
A* a = 0; // pretend this is valid
return foo( a, s1, s2 );
}
Note that I also changed the non-const reference to FooFunc to a value parameter. The rest of your code would then work as it is.
I don't have access to MSVC7 (I really do hope you've got 7.1 and not 7.0). You may need to use the 'Portable Syntax' as described in the boost.function documentation, e.g.:
typedef boost::function<bool , A *, unsigned, unsigned> FooFunc;
I am new to Boost.Threads and am trying to understand how to pass function arguments to the boost::thread_groups::create_thread() function. After reading some tutorials and the boost documentations, I understand that it is possible to simply pass the arguments to this function but I can't get this method to work.
The other method I read about is to use functors to bind the parameters to my function but that would create copies of the arguments and I strictly require that const references be passed since the arguments will be big matrices(this I plan to do by using boost::cref(Matrix) once I get this simple example to work).
Now, let's get down to the code:
void printPower(float b, float e)
{
cout<<b<<"\t"<<e<<"\t"<<pow(b,e)<<endl;
boost::this_thread::yield();
return;
}
void thr_main()
{
boost::progress_timer timer;
boost::thread_group threads;
for (float e=0.; e<20.; e++)
{
float b=2.;
threads.create_thread(&printPower,b,e);
}
threads.join_all();
cout << "Threads Done" << endl;
}
This doesn't compile with the following error:
mt.cc: In function âvoid thr_main()â:
mt.cc:46: error: no matching function for call to âboost::thread_group::create_thread(void (*)(float, float), float&, float&)â
/usr/local/boost_1_44_0/include/boost/thread/detail/thread.hpp: In member function âvoid boost::detail::thread_data<F>::run() [with F = void (*)(float, float)]â:
mt.cc:55: instantiated from here
/usr/local/boost_1_44_0/include/boost/thread/detail/thread.hpp:61: error: too few arguments to function
What am I doing wrong?
You can't pass arguments to boost::thread_group::create_thread() function, since it gets only one argument. You could use boost::bind:
threads.create_thread(boost::bind(printPower, boost::cref(b), boost::cref(e)));
# ^ to avoid copying, as you wanted
Or, if you don't want to use boost::bind, you could use boost::thread_group::add_thread() like this:
threads.add_thread(new boost::thread(printPower, b, e));
For more flexibility you can use:
-Lambda functions (C++11): What is a lambda expression in C++11?
threads.create_thread([&b,&e]{printPower(b,e);});
-Functors that store the arguments as const references.
struct PPFunc {
PPFunc(const float& b, const float& e) : mB(b), mE(e) {}
void operator()() { printPower(mB,mE); }
const float& mB;
const float& mE;
};
-std::bind (C++11) or boost::bind
I'm trying to make a type which can type-safely encapsulate arbitrary types. I got the idea in my head that this might be possible from this answer: 5 years later, is there something better than the "Fastest Possible C++ Delegates"? So far I have only succeeded in moving the problem, but I ran into an error that I can't find the root of.
The compiler seems to be telling me that it can't cast the value to the value's own type, which strikes me as bizarre.
I am running Mac OS X 10.6 with llvm-gcc 4.2 (gcc 4.2.1 front-end).
Suggestions of how to get rid of the void* or move it to a less consequential position are welcome, but this question isn't really about that.
The error:
$ g++ main.cpp
main.cpp: In static member function ‘static Stamp StampFactory<T>::make(T*) [with T = int]’:
main.cpp:33: instantiated from ‘Stamp makeStamp(T*) [with T = int]’
main.cpp:39: instantiated from here
main.cpp:26: error: could not convert template argument ‘t’ to ‘int*’
The code:
typedef void (*VoidFunc)(void*);
struct Stamp
{
Stamp(VoidFunc p)
{
this->press = p;
}
VoidFunc press;
};
template<typename T>
struct StampFactory
{
template<T* rvalue>
struct Pattern
{
void operator()(void* lvalue)
{
*dynamic_cast<T*>(lvalue) = *rvalue;
}
};
static Stamp make(T* t)
{
return Stamp(Pattern<t>()); // 28
}
};
template<typename T>
Stamp makeStamp(T* t)
{
return StampFactory<T>::make(t); // 33
}
int main(int argc, char** argv)
{
int i = 0;
Stamp s = makeStamp(&i); //39
}
The error is due to the fact that template arguments must be compile-time constants (or constexpr), and thus, cannot be a variable (or function parameter). It is allowed to have a pointer as a template argument, but there isn't much that you can feed to it because it needs to be a compile-time constant pointer value (and the only thing I can think of that qualifies is a char-pointer to a string literal). The general rule is simple: All template arguments must be known at compile-time, whether it is a type or a value. This excludes function parameters or other kinds of run-time variables.
I wish I could suggest an alternative to achieve what you desire, but I can't understand what you are actually trying to do at all.