#include <iostream>
#include <functional>
class Blub {
public:
int i = 0;
std::function<void()> create() const {
return [this]() {
this->i = 100;
};
}
};
int main() {
Blub blub = Blub();
blub.create()();
std::cout << blub.i << std::endl;
return 0;
}
I know that this is captured as const inside the lambda, because the method is marked const.
Is there still a way, aside from removing the constness of the method, to archive that i can modify member variables inside the lambda function?
Adding mutable keyword is not working.
You can declare the member variable i as mutable, so that it could change even if the object is declared as const:
class Blub {
public:
mutable int i = 0;
// ^^^^^^^
std::function<void()> create() const {
return [this]() {
this->i = 100;
};
}
};
Live here.
You can do the following workaround:
class Blub {
public:
int i = 0;
std::function<void()> create() const {
return [my_this=const_cast<Blub*>(this)]() {
my_this->i = 100;
};
}
};
but it is misleading to change a data member in a function which is actually marked as const so I wouldn't suggest designing your class in that way.
Check it out live.
N.B. It is worth to mention that const_cast is safe to use only if it's used for casting a variable that was originally non-const. If the variable is originally const, using const_cast could result in Undefined Behavior. So, in the following code (which the OP provided):
int main() {
Blub blub = Blub();
blub.create()();
std::cout << blub.i << std::endl;
return 0;
}
it is safe to use const_cast because object is originally made non-const. However, if we make it const like in the following code:
int main() {
const Blub blub = Blub();
blub.create()();
std::cout << blub.i << std::endl;
return 0;
}
it will result in an Undefined Behavior.
Related
I have a C-style function, which stores another function as an argument. I also have an object, which stores a method that must be passed to the aforementioned function. I built an example, to simulate the desired situation:
#include <functional>
#include <iostream>
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
std::function<void(int)> f;
void foo(int i) {
std::cout << i << "\n";
}
};
int main() {
TestClass t;
t.f = std::bind(&TestClass::foo, &t, std::placeholders::_1);
foo( t.f.target<void(int)>() );
return 0;
}
What is expected is that it will be shown on screen "2". But I'm having trouble compiling the code, getting the following message on the compiler:
error: const_cast to 'void *(*)(int)', which is not a reference, pointer-to-object, or pointer-to-data-member
return const_cast<_Functor*>(__func);
As I understand the use of "target", it should return a pointer in the format void () (int), related to the desired function through std :: bind. Why didn't the compiler understand it that way, and if it is not possible to use "target" to apply what I want, what would be the alternatives? I don't necessarily need to use std :: function, but I do need the method to be non-static.
This is a dirty little hack but should work
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
void foo(int i) {
std::cout << i << "\n";
}
};
static TestClass* global_variable_hack = nullptr;
void hacky_function(int x) {
global_variable_hack->foo(x);
}
int main() {
TestClass t;
global_variable_hack = &t;
foo(hacky_function);
return 0;
}
//can also be done with a lambda without the global stuff
int main() {
static TestClass t;
auto func = [](int x) {
t->foo(x); //does not need to be captured as it is static
};
foo(func); //non-capturing lambas are implicitly convertible to free functions
}
The following code causes segmentation fault, but I can't understand why:
#include <iostream>
#include <vector>
#include <functional>
class State {public:int x; int y; State(int _x,int _y):x(_x),y(_y){}};
typedef std::function<bool (const State &s)> FuncT;
std::vector<FuncT> funcs_outside;
class Manager
{
private: std::vector<FuncT> funcs;
public: void insert(const FuncT &g){funcs.push_back(g);}
// public: void insert(const FuncT &g){funcs_outside.push_back(g);}
public: FuncT getAnd()
{
// this should capture everything, no?
return [=](const State &s)
{
bool b=true;
for (const auto f:funcs)
// for (const auto f:funcs_outside)
{
b = b && f(s);
}
return b;
};
}
};
FuncT foo(void)
{
Manager m;
m.insert([=](const State &s){return s.x<=s.y;});
m.insert([=](const State &s){return s.x>=s.y;});
return m.getAnd();
}
int main(int argc, char **argv)
{
auto h = foo();
std::cout << "h(3,3) = " << h(State(3,3)) << "\n";
std::cout << "h(3,4) = " << h(State(3,4)) << "\n";
std::cout << "h(7,2) = " << h(State(7,2)) << "\n";
return 0;
}
The [=] should capture anything the lambda needs right?
When I replace funcs with funcs_outside, everything works well.
What am I doing wrong?
What am I doing wrong?
getAnd returns a function object from a member function, which captures and accesses members.
You call that member function on a local variable, and return the resulting function object to the outside of the scope. The members pointed by the function object no longer exist and calling the function object results in undefined behaviour.
When I replace funcs with funcs_outside, everything works well.
funcs_outside is a global object and you access it within its lifetime, so there is no problem.
how can I fix this?
You could for example capture a copy of the member instead:
return [funcs = this->funcs](const State &s)
I'm trying to execute a function that receives a parameter, which is a reference to an abstract class, through std::async but it seems that that is not valid for some reason. On the other hand, if I replace the mentioned reference by a pointer everything works.
Why does this happen? Is it generally better to pass abstract class parameters as pointers?
See the examples below:
Incorrect use of std::async
#include <iostream>
#include <future>
class AbsClass {
public:
virtual int f() = 0;
};
class ImplClass : public AbsClass {
public:
int f() override { return 21; }
};
int func(AbsClass &asbclass) {
return 210 + asbclass.f();
}
int main() {
ImplClass ic;
AbsClass &ac = ic;
// This causes a compilation failure:
std::future<int> res = std::async(&func, ac);
std::cout << res.get() << std::endl;
}
Failure displayed
/usr/include/c++/7/future:1745:5: error: invalid abstract parameter type ‘AbsClass’
main.cpp:4:7: note: because the following virtual functions are pure within ‘AbsClass’:
class AbsClass {
^~~~~~~~
main.cpp:6:17: note: virtual int AbsClass::f()
virtual int f() = 0;
Correct use of std::async
#include <iostream>
#include <future>
class AbsClass {
public:
virtual int f() = 0;
};
class ImplClass : public AbsClass {
public:
int f() override { return 21; }
};
int func(AbsClass *asbclass) {
return 210 + asbclass->f();
}
int main() {
ImplClass ic;
AbsClass &ac = ic;
std::future<int> res = std::async(&func, &ac);
std::cout << res.get() << std::endl;
}
The arguments needs to be stored, which means they are copied. And references can't be copied.
Therefore a reference wrapper was introduced, that can store references while also being able to be copied. You can use it with the helper function std::ref and std::cref:
std::future<int> res = std::async(&func, std::ref(ac)); // Pass ac by reference
Flex Ferrum post a code sample here (I think it is Minimal, Complete, and Verifiable enough):
#include <iostream>
#include <functional>
using namespace std;
class Bang
{
public:
Bang(int i = 0) : m_val(i)
{
m_foo = [this] {std::cout << m_val << std::endl;};
}
~Bang()
{
m_val = -1;
}
void Foo()
{
m_foo();
}
private:
int m_val;
std::function<void ()> m_foo;
};
Bang GetBang()
{
return Bang(100500);
}
int main() {
Bang b(100500);
b.Foo();
b = GetBang();
b.Foo();
return 0;
}
Our nice Flex also offer a live demo
After a rough look, I thought it will output 100500, but the real output is:
-1
Why? What's behind it?
How to fix it?(output 100500, not -1)
I have written some my own reasonings in the ask box, but found it is more fit to be posted as an answer(will make the question too long). If my answer is wrong, please correct it and more answers are welcome
Ah, it should blame the destructor of temporary - Bang(100500), which returns form GetBang, is prvalue, and has temporary object lifetime.
[this] will be stored as reference of *this, like this:
class Lambda
{
public:
void operator()() const
{
//output
}
private:
Bang& bang;
public:
Lambda(Bang& bang) : bang{bang}
{
}
} lambda{*this};
...
m_foo = lambda;
Because here is no RVO, so, the temporary Bang(100500) will first be assigned to b, then be destroyed.
Custorm operator(), constructor, and destructor to output some information:
#include <iostream>
#include <functional>
using namespace std;
class Bang
{
public:
Bang(int i = 0) : m_val(i)
{
std::cout << "Bang(int i = 0) m_val address is " << &m_val << '\n';
class Lambda
{
public:
void operator()() const
{
std::cout << "operator() m_val address is " << &bang.m_val << '\n';
std::cout << bang.m_val << std::endl;
}
private:
Bang &bang;
public:
Lambda(Bang &bang) : bang{bang}
{
}
} lambda{*this};
m_foo = lambda;
}
~Bang()
{
std::cout << "~Bang()\n";
m_val = -1;
}
void Foo()
{
m_foo();
}
private:
int m_val;
std::function<void()> m_foo;
};
Bang GetBang()
{
return Bang(100500);
}
int main()
{
Bang b;
b = GetBang();
b.Foo();
return 0;
}
live demo
Output:
Bang(int i = 0) m_val address is 0x7ffd202c48b0
Bang(int i = 0) m_val address is 0x7ffd202c48e0
~Bang()
operator() m_val address is 0x7ffd202c48e0
-1
~Bang()
shows:
dtor will be called before output, That means that the temporary object has been destroyed.
m_value's address doesn't change.
The two guaranteed we still access the temporary's m_value from the b's m_foo().
It should be Undefined Behaviour to access an object which has be destroyed, but no warning and errors required.
Update
To solve the problem, there two solutions:
Like #Killzone Kid points out, capture with an initializer: [bang = *this]. This requires c++14.
More simpler way to capture of the current object by-copy: [*this]. This requires c++17. live demo
You probably want to pass current object to lambda by value *this so that it can be stored and copied when you copy assign Bang. Passing pointer this will store and copy pointer to the temp object that has been destroyed when you copy assign Bang.
This works as it should:
#include <iostream>
#include <functional>
class Bang
{
public:
Bang(int i = 0) : m_val(i)
{
m_foo = [bang = *this] { std::cout << bang.m_val << std::endl; };
}
~Bang()
{
m_val = -1;
}
void Foo()
{
m_foo();
}
private:
int m_val;
std::function<void()> m_foo;
};
Bang GetBang()
{
return Bang(100500);
}
int main()
{
Bang b;
b = GetBang();
b.Foo();
return 0;
}
Demo: https://ideone.com/LUDrBb
assuming that I have a generic class A
class A {
...
int a; // a member
void foo() const{...} // a member function qualified as const
...
};
this implies that if I declare an instance of A like A k; and then I call k.foo(); the this pointer that is acting on/inside that call to foo is something of type const A * const .
Now I would like to know why the code in this blog post works, especially about why this doesn't apply to global variables.
My explanation is about an hidden operation about pointer aliasing, like the this pointer being copied implicitly and during this copy the result is not const anymore ( for some reason ... ) but it's still a this pointer meaning that is a pointer to the same instance.
My question is about: what really const does if it's applied after the declaration of an interface for a member function ? Do you have a specific answer for the linked blog post ?
code from the blog
#include <iostream>
class counter {
public:
int i;
counter();
int inspect() const;
void increment();
};
counter sigma_inspect; // sigma_inspect is global
counter::counter() { i = 0; }
int counter::inspect() const {
sigma_inspect.increment();
return i;
}
void counter::increment() {
++i;
return;
}
int main(void) {
counter a;
std::cout << a.inspect() << "\n";
std::cout << sigma_inspect.inspect() << "\n";
std::cout << sigma_inspect.inspect() << "\n";
return 0;
}
The call in the blog post is using sigma_inspect which is non-const and it is calling a non-const method on it instead of calling said method through the const this pointer. So what? The author seems to expect magic instead of the obvious of what he wrote. It's like having
T* t = ...;
const T* ct = t;
t->foo(); // foo() is not const, but hey,
// I also have a const pointer now (ct),
// so why can I still use this???
Generally, if someone calls C++ stupid it tells you more about the author instead of the language :)