I'm currently doing the boost asio tutorial, and I'm running into a problem with bind:
Of course the default code works: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/tutorial/tuttimer3/src.html
but when I'm trying to use references instead of pointers in the print function, I get compiler errors:
error: use of deleted function ‘asio::basic_deadline_timer<boost::posix_time::ptime>::basic_deadline_timer(const asio::basic_deadline_timer<boost::posix_time::ptime>&)’
t.async_wait(boost::bind(do_sth1,asio::placeholders::error,t, count));
My modified code:
#include <iostream>
#include <asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
void do_sth1(const asio::error_code& ,asio::deadline_timer& t, int& count )
{
if(count<=5){
(count)++;
t.expires_at(t.expires_at()+boost::posix_time::seconds(2));
t.async_wait(boost::bind(do_sth1,asio::placeholders::error,t, count));
}
std::cout<<count<<"\n";
}
void do_sth2(const asio::error_code& ){
std::cout<<"Yo\n";
}
int main()
{
int count =0;
asio::io_service io;
asio::deadline_timer t1(io, boost::posix_time::seconds(1));
asio::deadline_timer t2(io, boost::posix_time::seconds(3));
t1.async_wait(boost::bind(do_sth1,asio::placeholders::error,t1,count));
t2.async_wait(do_sth2);
io.run();
std::cout << "Hello, world!\n";
return 0;
}
Deleted functions have been introduced only recently to C++ -- see e.g. here on MSDN. Previously this was worked around by declaring the method as private. Whatever the way it is done, it means that someone declared an otherwise implicitly created method as deleted, so that nobody could (even accidentally) call it. This is used for example to disallow copying objects which it does not make sense to copy (by deleting the copy constructor).
This is exactly your case, as the deleted function's name ‘asio::basic_deadline_timer::basic_deadline_timer(const asio::basic_deadline_timer&) indeed reveals that a copy constructor was supposed to be called. boost::deadline_timers cannot be copied.
But why is the timer object being copied? Because boost::bind by default stores the bound parameters by value. If you need to pass a reference, you need to use boost::ref as follows:
t1.async_wait(boost::bind(do_sth1,asio::placeholders::error,boost::ref(t1),boost::ref(count)));
I.e. even for the count variable, which would not cause a compiler error, but wouldn't work (would not modify the variable in main()).
Related
I am trying to use an API which sets a value of a variable based on an HTTP call. The function in which I can set the variable which will be set upon an HTTP Call is of type T&&. I would like to access this variable on a different thread. I tried to simplify the problem and represent it in the following code, as two threads, accessing a variable the same way.
#include <iostream>
#include <thread>
#include <chrono>
class Values
{
public:
int i;
std::string s;
};
template<typename T>
void WriteCycle(T&& i)
{
using namespace std::chrono_literals;
while (true)
{
i++;
std::cout << i << std::endl;
std::this_thread::sleep_for(500ms);
}
}
template<typename T>
void ReadCycle(T&& i)
{
using namespace std::chrono_literals;
while (true)
{
std::cout << i << std::endl;
std::this_thread::sleep_for(500ms);
}
}
int main() {
auto v = new Values();
std::thread t1(WriteCycle<int>, v->i);
std::thread t2(ReadCycle<int>, v->i);
t1.join();
t2.join();
}
Currently the read thread does not see any change in the variable. I read up an perfect forwarding, move semnatics and forwardin references, but I did not get it (I mostly program dotnet, my c++ knowledge is pre C++11). I tried all combinations of std::move, std::ref and std::forward but I cannot get the read thread to see the change of the write thread. Is there a way to solve this, without changing the T&& input type of the functions (since that is part of the API I am trying to use)? How to solve this in a thread-safe way?
Such notation:
template<typename T>
void WriteCycle(T&& i)
Doesn't really mean an rvalue reference, it means a universal reference, which could be an lvalue reference or rvalue reference depending on what kind of data you pass.
In your case it turns into just an lvalue reference, so it has nothing to do with move semantic. The problem is that thread constructor is not quite friendly with references and you may want just to use std::ref to get it round:
auto myRef = std::ref(v->i);
std::thread t1(WriteCycle<&int>, myRef);
std::thread t2(ReadCycle<&int>, myRef);
However it still won't be perfect, because you want to synchronize between threads with use of mutexes or atomic values
I'm having a function that takes a weak_ptr<> and I pass my shared_ptr<> in the function.
#include <memory>
#include <iostream>
void takeweak(std::weak_ptr<int> wp) {
std::cout << wp.use_count() << std::endl; // prints 1
}
int main() {
takeweak(std::make_shared<int>());
return 0;
}
Is this working by luck or it is working by design?
Do I have a copy of the shared pointer living throughout the main() scope function? Or Will the shared pointer live throughout the scope of takeweak() body (up to its stack unwind)?
Is it probable that this behavior going to break in a new version of the compiler or the language standard?
Related question: Different behaviour while passing shared_ptr to weak_ptr in thread functions and normal functions
I was looking to an exercise I did, specifically a class "threads manager" which manage threads (omg really? lol) by storing them inside an array of "typedef void *HANDLE;" declared inside a struct GROUP.
So I already made it working, but I saw that I was converting the "HANDLE", so "void*", by "reinterpret_cast" conversion to "std::thread*".
After I saw that I worried: how and can I convert it directly to an std::thread object?
I did this code for example:
#include <iostream>
#include <thread>
typedef void *HANDLE;
class thread_obj {
public:
void operator()(int x){
for(int i = 0x0; i < x; i++){
std::cout << "i = " << i << std::endl;
}
}
};
int main(){
std::thread thr(thread_obj(), 0x3);
HANDLE test = &thr;
std::thread *p_thr = reinterpret_cast<std::thread*>(test);
p_thr->join();
return 0x0;
}
This is the original code.
If instead I do:
std::thread p_thr = reinterpret_cast<std::thread&>(test);
or:
std::thread p_thr = *reinterpret_cast<std::thread*>(test);
or:
std::thread *temp = reinterpret_cast<std::thread*>(test);
std::thread p_thr = *temp;
I always get:
error: use of deleted function ‘std::thread::thread(std::thread&)’
On "reinterpret_cast" line for the first and second case, and on the following assignment line for the third.
Now I suppose the problem is with the copy constructor called.
I searched a little and I opened the thread class and I found it:
thread(thread&) = delete;
So :/ searching a little I only found the solution on which you override the copy constructor.
In this case I think a solution could be make a superclass an re-declare this deleted constructor, right? But this is just a waste of time :/
So is there a way to convert this "void*" to "std::thread" object, again to a "std::thread" object?
If yes or no can you explain me in detail please?
Thank you so much
have a nice day and coding :D
What you really need is
std::thread& ref_thr = *reinterpret_cast<std::thread*>(test);
// ^ declare a reference to a std::thread
and then you can use ref_thr just like you would use a normal object.
As you've found, the copy constructor for std::thread is deleted, so if you actually want to create a thread object from test, then you need to move the casted object into new_thr like
std::thread new_thr = std::move(*reinterpret_cast<std::thread*>(test));
but this means that the object pointer to by test is no longer usable as it was moved into new_thr. This is why you want to use a reference, unless you actually want to move it.
I have the following code:
#include <iostream>
#include <memory>
#include <vector>
class Test
{
public:
Test() {}
~Test() { std::cerr << "Delete\n"; }
};
std::vector<std::shared_ptr<Test>> makeList()
{
std::vector<std::shared_ptr<Test>> list;
list.push_back(std::make_shared<Test>(Test()));
return std::move(list);
}
int main(int argc ,char **argv)
{
std::vector<std::shared_ptr<Test>> list;
std::cerr << "Before\n";
list = makeList();
std::cerr << "After\n";
return 0;
}
Which I compile with:
clang++ -std=c++14 -o ptr ptr.cpp
The output is:
Before
Delete
After
Delete
My question is: why is there an object being deleted in the makeList function? My assumption was that the list from the function would be moved into list from main and that therefore no object would be deleted/recreated in the process?
Can this be avoided (as obviously this code is not optimum)?
2 Changes:
std::vector<std::shared_ptr<Test>> makeList()
{
std::vector<std::shared_ptr<Test>> list;
// make_shared does not need a copy of an object, just constructor arguments
list.push_back(std::make_shared<Test>());
// return std::move(list) will defeat RVO. Never do that.
return list;
}
So, the important part is :
list.push_back(std::make_shared<Test>(Test()));
->
list.push_back(std::make_shared<Test>());
Just for clarification because I had the same today, and I had trouble seeing the difference.
list.push_back(std::make_shared<Test>(Test()));
Here temporary is created with Test(). Then copy c-tor for Test is invoked and temporary is destroyed. It is the first destructor call.
The second destructor call appears in the end of the program when list is destroyed.
The right form to avoid temporary creation is:
list.push_back(std::make_shared<Test>());
Besides you shouldn't use std::move returning the value because compiler cannot apply Return value optimisation in such case.
The line list.push_back(std::make_shared<Test>(Test())); makes a temporary Test and then moves it into the actual Test constructed by std::make_shared<T>. This temporary is then destroyed.
std::make_shared<T> requires the arguments to be used in construction of T. For a default constructed T simply provide no arguments.
The correct use, in this case, is this:
list.push_back(std::make_shared<Test>());
due project's requirements, by this week I'm shifted from Java to C++. I'm facing a lot of trouble, but maybe the greater is the "pass-by-value" and... obviously pointers :)
Now I have a big doubt regard the destiny of an object instantiated inside an the constructor of another object. Here my simple SSCCE composed by an header and a cpp file:
#pragma once
#include <map>
class MapReferenceHolder
{
std::map<int, char*>* mapPointer;
public:
MapReferenceHolder();
~MapReferenceHolder();
void setMap(std::map<int,char*>* map);
void addSomeElementToMap();
void MapReferenceHolder::printMap();
};
Here the cpp file containing the main:
#include "MapReferenceHolder.h"
#include <iostream>
using namespace std;
std::map<int, char*>mymap;
MapReferenceHolder::MapReferenceHolder()
{
setMap(&mymap);
}
MapReferenceHolder::~MapReferenceHolder()
{
}
void MapReferenceHolder::setMap(std::map<int, char*>* map){
mapPointer = map;
}
void MapReferenceHolder::addSomeElementToMap(){
(*mapPointer)[0] = "stringONe";
(*mapPointer)[1] = "stringTwo";
}
void MapReferenceHolder::printMap(){
std::map<int, char*>::iterator it = mapPointer->begin();
while (it!=mapPointer->end()){
cout << it->first << " -> " << it->second << "\n";
it++;
}
}
int main(){
MapReferenceHolder m;
m.addSomeElementToMap();
m.printMap();
cin.get();
return 0;
}
This simple example run without problem. But if I move the mymap instantiation inside the constructor, i.e.
MapReferenceHolder::MapReferenceHolder()
{
std::map<int, char*>mymap;
setMap(&mymap);
}
I get thw folowing error:
Unhandled exception at 0x00B2BD3B in Project1.exe: 0xC0000005: Access violation reading location 0xCCCCCCD0.
I guess this is due to the fact that an instance of an object live only inside the block in which is defined. But I'm passing the address of object, so it is still alive!?? Or the compiler destroy it in any case? And more important... is it, then, right create a global variable to store an object instance. How I can use correctly the constructor? I know this is a "newbie" question but I'm try to match project's development needs and my spare time to study is really little. Any help will be great appreciated.
Regards,
microvo
The object is destroyed at the end of the constructor. so you have saved a pointer that is no longer valid.
You need to consider ownership in C++ (Java has a cycle detecting garbage collector so gives you a lot of leeway).
If MapReferenceHolder owns the std::map you should make it a value rather than a pointer, you can always use a reference to it if you need a pointer for some reason. Also get rid of your constructor and destructor unless they contain actual code.
Alternatively you could call delete mapPointer in your destructor but that is adding extra code for no benefit in simple cases like this IMO.
If MapReferenceHolder does not own std::map then you need to require the pointer be passed in and somehow track the lifetime of it somewhere outside this class.
The map object no longer exists once it goes out of scope, regardless of any pointers that hold its address - these are no longer valid. I suggest a search for "constructor initializer list" might help you.