my simple test code is as:
// t.cpp
#include <iostream>
#include <thread>
#include <chrono>
class test
{
private:
public:
void fcn1();
void fcn2();
uint8_t i = 0;
};
void test::fcn1()
{
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(999));
std::cout << "hihi " << (float)i++ << std::endl;
}
}
void test::fcn2()
{
std::cout << "yoyo " << (float)i++ << std::endl;
}
test t;
std::thread tt(&test::fcn1, t);
int main()
{
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
t.fcn2();
}
return 0;
}
compile and run by g++ ./t.cpp -o t -lpthread; ./t, result is like
hihi 0
yoyo 0
hihi 1
yoyo 1
hihi 2
yoyo 2
hihi 3
...
i expect the result should be:
hihi 0
yoyo 1
hihi 2
yoyo 3
hihi 4
yoyo 5
...
looks like the cpp thread of instance member-fcn reset the member-variable?
why not the i is shared by fcn1 and fcn2?
the demo code is a simplification of my real useage, but faces the same problem,
what's wrong with my code? thanks very much.
From std::thread:
args_copy... are objects of types std::decay<Args>::type... and constructed from std::forward<Args>(args)....
...
The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g., with std::ref or std::cref).
So arguments are copied by default, including the this argument to a pointer-to-member function. You can wrap it in std::ref to get a reference explicitly.
std::thread tt(&test::fcn1, std::ref(t));
std::thread makes a copy of all of its constructor arguments. That means that std::thread tt(&test1::fcn1, t) makes a copy of t and calls fcn1 on the copy.
To avoid that you need to pass a pointer or std::reference_wrapper to t:
std::thread tt(&test1::fcn1, &t);
Demo
Note that even with this change your program's behavior is undefined since you have a data race on t.i. You should use std::atomic<uint8_t> instead to avoid that race.
Related
I am trying to do something similar to the last code in this
In the code however you see that
vec_thr.emplace_back(&Test::testme, std::move(t1), std::cref(str)); is called inside the main function.
I would like to do that from a member function of the object Test.
So I did
#include <thread>
#include <string>
#include <vector>
#include <iostream>
class Test
{
private:
public:
void testme(const std::string& _str)
{
std::cout << "Hello " + _str << std::endl;
}
void testFurther(const std::string& _str){
std::vector<std::thread> vec_thr;
// pass the constructor parameters you would have passed to std::thread
// to the emplace_back() function - they are forwarded to the thread that
// is constructed "in place" inside the vector
for(int i=0;i<2;i++){
//HERE I am trying how to write this correctly trying the following:
// vec_thr.emplace_back(&Test::testme, std::move(t1), std::cref(str));
vec_thr.emplace_back(testme, std::move(this), std::cref(_str));
// vec_thr.emplace_back(testme, std::cref(_str));
}
// Don't forget to join all your threads to make sure
// they complete before moving on/exiting
for(auto& t: vec_thr)
t.join();
}
};
int main()
{
const std::string str = "there";
Test t1/*, t2*/;
t1.testFurther(str);
}
However it is not working. I got the error message
error: invalid use of non-static member function
Is there a way to be able to do this.
I want to do the exact same thing that was done originally from the main function
It seems I have solve the problem by changing the class Test function testFurther to
void testFurther(const std::string& _str){
std::vector<std::thread> vec_thr;
// pass the constructor parameters you would have passed to std::thread
// to the emplace_back() function - they are forwarded to the thread that
// is constructed "in place" inside the vector
for(int i=0;i<2;i++){
// vec_thr.emplace_back(&Test::testme, std::move(t1), std::cref(str));
// vec_thr.emplace_back(testme, std::move(this), std::cref(_str));
// vec_thr.emplace_back(&testme, this, std::cref(_str)); // ISO forbid taking the address of an unqualified or parenthesized non-static member function
vec_thr.emplace_back(&Test::testme, this, std::cref(_str)); //THIS WORKS
// vec_thr.emplace_back(testme, std::cref(_str));
}
// Don't forget to join all your threads to make sure
// they complete before moving on/exiting
for(auto& t: vec_thr)
t.join();
}
with this it seems to be working well.
I just wonder why I have to use &Test::testme since Test is the name of the class not of an object instance
This question already has answers here:
What is move semantics?
(11 answers)
Closed 3 years ago.
I feel pass by reference and a move has a same result. In the below example both move semantic and pass by reference has same outcome. I was assuming when we use move semantics the ownership is passed on the the function and in main the variable does not hold any value.
#include <iostream>
using namespace std;
void move_function(int&& a)
{
cout<<"a:"<<a<<endl;
a++;
cout<<"a:"<<a<<endl;
}
void function(int& val)
{
val++;
cout<<"val:"<<val<<endl;;
}
int main()
{
int a = 100;
move_function(move(a));
cout<<"main a:"<<a<<endl;
function(a);
cout<<"main a:"<<a<<endl;
return 0;
}
can someone give me some light on my confusion. Where has my understanding about move gone wrong?
Move() gives ownership to your new object. It is useful in multi-threading where you want to pass the ownership of a mutex to a lock.
Pass by reference is a way of passing objects between functions by creating an alias.
Reference create an alias of the varialbe that is passed. Move is something different. Move "steals" the value that a variable holds.
For example if you have
void foo(void)
{
std::shared_ptr<int> p = std::make_shared<int>();
std::shared_ptr<int> ps = std::move(p);//after execution p has expired
std::cout << "count:" << ps.use_count() << std::endl;
std::cout << "count:" << p.use_count() << std::endl;
std::shared_ptr<int> ps2 = ps;// simple copy,after executuion the reference count
// is 2
std::cout << "count:" << ps2.use_count() << std::endl;
}
When this routine will be executed the ps shared pointer will steal the value of the p and p will be espired.
But when the ps2 is defined , the content of the ps will be copied to this and reference count will be increased . The new value will be 2.
class test
{
int a;
static int cnt;
public:
test()
{
a=0;
cout <<++cnt;
}
test( int p)
{
a=p;
cout <<++cnt;
}
~test()
{
cout<<cnt--;
}
};
int test::cnt;
void main()
{
test ob,ob1(10);
ob = test();
test();
}
In this code snippet ob=test(); how ob can be assigned a function test.Test is a class and we are invoking it like a function.How can this be possible
Functions return void, objects, references or pointers to objects, that can generally be assigned to variables in your program. In this particular case, you are calling the test class object constructors and possibly encountering undefined behavior on the final call. I need to investigate further on the possible UB, the C++ standard has changed twice since I last read it, VS-2017 may not be the best oracle, and my C++ foo is little weak.
As far as I recall, there's more than one way to initialize an object in C++ and your instructor has obviously given you an assignment to learn this first hand.
test ob; // Invokes default constructor on test
test ob(); // Invokes default constructor on test.
test ob = test::test(); // Invokes default constructor on test.
It's always good to experiment with your code and get it to output usable diagnostics. I tweaked it a bit to get more organized output and force the app to wait on user input prior to exiting. You should also learn to use your debugger. You can learn a lot by simply stepping through your own code.
#include <iostream>
#include <cstdlib>
class test
{
int a;
static int cnt;
public:
test()
{
a = 0;
cnt++;
std::cout << cnt << std::endl;
}
test(int p)
{
a = p;
cnt++;
std::cout << cnt << std::endl;
}
~test()
{
std::cout << cnt << std::endl;
cnt--;
}
};
int test::cnt = 0;
int main(void)
{
{
test ob; // test::cnt is incremented, 1 is displayed on the console.
test ob1(10); // test::cnt is incremented, 2 is displayed on the console.
ob = test::test(); // test::cnt is incremented, 3 is displayed on the console.
// The following instantiates a temporary test object,
// the constructor is called, but test::cnt is not incremented on my system.
// Seems we might be in undefined behavior territory?
test::test();
}
system("pause");
}
Notice that I added an additional context to 'main()'. You can't rely on destructors outputting anything to the console after the end of 'main()' which is where your objects are destructed. Moving all the objects into the additional {} context, forces them to be constructed and destroyed therein, allowing us to a complete picture of what's going on at our console output.
The output on my Windows box for the above code is:
1
2
3
3
3
3
2
1
Press any key to continue . . .
I expected a count to 4 and then a count down from 4. That last call is definitely confusing me. If nobody chimes in with a definitive explanation, I'll look into it as soon as I can.
I'm trying to use lambdas inside a project but I think I'm missing something about the closure's scope. I tested this piece of code which in some way is a simplification of my problem.
#include <iostream>
#include <functional>
using namespace std;
void tester_wrapper(std::function<int(void)> cb, int counter){
if (counter == 10)
return;
else{
cout << cb() << endl;
tester_wrapper(cb, counter + 1);
}
}
void tester(std::function<int(void)> cb){
tester_wrapper(cb, 0);
}
int main()
{
auto getNum = ([](int starter) {
return [starter]() mutable {
return ++starter;
};
})(1);
tester(getNum);
tester(getNum);
}
After the first call to tester the captured variable starter is reset so that the same output is printed twice.
What should I do in order to avoid this behaviour of the inner counter(starter) of the lambda? Essentially the second call to tester has to print 10 numbers starting from 12 instead of 2.
EDIT
Thank you for the answers. I have not considered that I was passing a copy to tester_wrapper, so I've found this solution:
#include <iostream>
#include <functional>
using namespace std;
std::function<int(void)> mylambda(int starter){
return [starter]() mutable {
return ++starter;
};
}
void tester_wrapper(const std::function<int(void)>& cb, int counter){
if (counter == 10)
return;
else{
cout << cb() << endl;
tester_wrapper(cb, counter + 1);
}
}
void tester(const std::function<int(void)>& cb){
tester_wrapper(cb, 0);
}
int main()
{
/*auto getNum = ([](int starter) {
return [starter]() mutable {
return ++starter;
};
})(1);*/
auto getNum = mylambda(1);
tester(getNum);
tester(getNum);
}
However, now I can't understand why the old getNum print the same output while it's different using an "external" function, which is mylambda.
(Am I supposed to post a new question for this?)
The variable isn't reset, it's a different copy of the variable. In fact, there are a bunch copies. The first is in the state of the lambda you create. The second is created when the first std::function is constructed. You must remember that it copies the callable it receives into itself. So each invocation of tester starts a chain of copies. One way to get around it, is to pass the lambda inside a std::reference_wrapper.
tester(std::ref(getNum));
tester(std::ref(getNum));
The reference wrapper will be copied, but all copies will refer to the same lambda object, getNum.
Now, assuming you intend to create many different objects like getNum, a std::function and the type erasure it provides are a reasonable course of action to avoid possible code bloat. The thing to remember is to not create superfluous copies. So tester accepting by value is legitimate, but tester_wrapper should accept by reference instead. That way, you'll only pay for the type erasure in the one place you need it, at the API boundary.
The argument getNum you're passing to tester is being copied by std::function<int(void)>. That is, std::function<int(void)> does not store the original getNum, instead it stores a copy.
#StoryTeller and #Edgar already suggested two solutions. Here is third one:
template<typename Callback>
void tester_wrapper(Callback && cb, int counter){
if (counter == 10)
return;
else{
cout << cb() << endl;
tester_wrapper(cb, counter + 1);
}
}
template<typename Callback>
void tester(Callback && cb){
tester_wrapper(std::forward<Callback>(cb), 0);
}
Now there is no copy, as both functions accept the argument by reference.
By the way, this code is likely to be faster than the other two, as other two continue to use std:function which has one virtual call or equivalent to invoke the stored callable.
Hope that helps.
One possible solution is to create a separate variable starter and then capture it by reference so the lambda changes the actual variable:
auto starter = 0;
auto getNum = [&starter]() {
return ++starter;
};
Then you just call:
tester(getNum);
tester(getNum);
The output will be numbers from 1 to 20.
Given the following test code
#include <iostream>
#include <tr1/functional>
using namespace std;
struct cl {
cl(){ cout << " cl()\n"; }
cl(const cl& from){ cout << " cl()[copy]\n"; }
~cl(){ cout << " ~cl()\n";}
};
void f1(const cl& data){}
void f2(const cl* pData){}
int main(int c, char** a)
{
cout << "enter:\n";
cl data;
cout << "ref:\n";
tr1::bind(&f1, data);
cout << "ptr:\n";
tr1::bind(&f2, &data);
cout << "exit:\n";
return 0;
}
I get the following output:
$ g++ tr1BindDtorTest.cpp && ./a.out
enter:
cl()
ref:
cl()[copy]
cl()[copy]
cl()[copy]
~cl()
~cl()
~cl()
ptr:
exit:
~cl()
When I create a binding involving references to my class/struct objects are created and destroyed multiple times.
Same exact test but with pointers there are no such objects
I can't see why the behaviour will be different between pass by value & reference, I always thought of reference as syntactic sugar for pointer, and so reasoned that the behaviours should be identical.
Anyone care to explain?
[g++ 4.4.6 linux & 4.2.1 on macos]
Instead of this:
tr1::bind(&f1, data);
You need this:
tr1::bind(&f1, tr1::ref(data));
Boost has the same thing: boost::ref() must be used inside boost::bind() if you want the bound function object to store a reference to the data. Otherwise, the data will always be copied into the bound function object produced by bind().
See cppreference documentation:
The arguments to bind are copied or moved, and are never passed by
reference unless wrapped in std::ref or std::cref.