I'm coming back to c++ from a long absence, and am picking up c++11 and boost::asio at the same time.
After GotW #93 and #94, I'm naturally fired up about using auto.
Imagine my disapointment when this doesn't compile:
auto io = boost::asio::io_service{};
but I must use this instead:
boost::asio::io_service io{};
Why does the second compile, but the first not? The error I'm getting is
Call to implicitly-deleted copy constructor of 'boost::asio::io_service'
boost::asio::deadline::timer exhibits the same behavior, but boost::posix_time::seconds does not.
(I'm using xcode + clang + boost 1_55_0).
Full compiling example, modified from the boost asio tutorial:
#include <iostream>
#include <memory>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
namespace asio = boost::asio;
int main(int argc, const char * argv[]) {
using error_code = const boost::system::error_code;
asio::io_service io{};
asio::deadline_timer t{io, boost::posix_time::seconds{2}};
int count = 0;
std::function<void (const error_code&)> fn = [&](const error_code& e) {
if (count < 5) {
std::cout << "Hello World" << std::endl;
++(count);
t.expires_at(t.expires_at() + boost::posix_time::seconds{1});
t.async_wait(fn);
}
};
t.async_wait(fn);
io.run();
std::cout << "Final count is " << count << std::endl;
return 0;
}
The class asio::io_service derives from noncopyable, which means the copy constructor has been intentionally made inaccessible. This statement won't work for the same reason:
boost::asio::io_service io = boost::asio::io_service{};
In this instance, the problem is not because of the auto keyword, but lack of access to the required constructor. The tutorial code uses the normal constructor, which is public, and so compiles fine.
The error is pretty self-explanatory, it has nothing to do with the use of auto. The following code will produce a similar error message:
struct foo
{
foo() = default;
foo(foo const&) = delete;
};
foo f = foo{};
The last line above requires an accessible copy-constructor (even if the compiler elides the copy).
boost::asio::io_service's copy-constructor is implicitly deleted, probably due to the presence of one or more non-copyable data members or base classes. You already have the right solution to fix the error:
asio::io_service io{};
Related
I have to maintain two different legacy projects with some shared source code, one of them is tied to boost v1.69 and the other one is tied to boost v1.71.
The problem here is that compiler is working with v1.71 and failing with v1.69 when using some boost::asio sockets class.
The other restriction is to use c++17 or earlier, so sadly c++20 fancy features are not allowed here.
Here is a minimal (really minimal) functional example, just to show the problem. Do not expect this sample code doing anything, not even trying to connect.
Godbolt link: https://godbolt.org/z/fj4E8qhxT
#include <map>
#include <boost/asio.hpp>
namespace tcpsocket
{
using boost::asio::ip::tcp;
class client
{
public:
client(boost::asio::executor executor) : socket(executor) {}
private:
tcp::socket socket;
};
}//namespace tcpsocket
int main()
{
boost::asio::io_context ioc;
std::map<int, tcpsocket::client> clients;
//This is working with boost v1.71 but failing with boost v1.69
auto id{125};
auto[it, ok] = clients.emplace(id, ioc.get_executor());
if (ok)
auto& client = it->second;
}
Is it using a boost::asio::io_context& (watch the reference &) a very naive solution solution to solve this problem? I mean, was there any hidden problem with that in a single threaded application?
Well, there is at least one problem, the change from get_io_context() to get_executor() between versions.
Any help with this?
pre-1.70.0 Asio doesn't support executors in IO objects yet:
Changelog
Added custom I/O executor support to I/O objects.
All I/O objects now have an additional Executor template parameter. This template parameter defaults to the asio::executor type
(the polymorphic executor wrapper) but can be used to specify a
user-defined executor type.
I/O objects' constructors and functions that previously took an asio::io_context& now accept either an Executor or a reference to a
concrete ExecutionContext (such as asio::io_context or
asio::thread_pool).
I'd go with the old interface:
Live On Compiler Explorer
#include <map>
#include <boost/asio/version.hpp>
#include <boost/asio.hpp>
#include <iostream>
namespace tcpsocket
{
using boost::asio::ip::tcp;
using boost::asio::io_context;
class client
{
public:
client(io_context& ctx) : socket(ctx) {}
private:
tcp::socket socket;
};
}//namespace tcpsocket
int main()
{
std::cout << BOOST_ASIO_VERSION << " " << BOOST_VERSION << "\n";
boost::asio::io_context ioc;
std::map<int, tcpsocket::client> clients;
//This is working with boost v1.71 but failing with boost v1.69
auto id{125};
auto[it, ok] = clients.emplace(id, ioc);
if (ok)
auto& client = it->second;
}
Prints either
101202 106900
or
101401 107100
I am working on an old source code project which originally was written using MSVC 2008 and Boost 1.42, today I'm trying to port this to MSVC 2017 with Boost 1.73
There are many issues to resolve, one of which is below:
Severity Code Description Project File Line Suppression State
Error C3536 'binding': cannot be used before it is initialized Process Control Service Group processscope.cpp 197
The line that this occurs on:
auto binding = boost::bind(&IProcessChangeObserver::notify, _1, m_scope, change);
std::for_each(observers.begin(), observers.end(), binding);
Originally the assignment to binding was inline as the third parameter, it gives the same error. I can see why this is a problem, I cannot see why it ever worked?
Is there another way to write the above without the triggering a warning?
I've tried replacing with a standard loop:
for( std::list<boost::intrusive_ptr<IProcessChangeObserver> >::iterator itProc=objservers.begin();
itProc!=objservers.end(); itProc++ ) {
boost:bind(&IProcessChangeObserver::notify, itProc, m_scope, change);
}
To be honest I'm not 100% sure if this is a like for like replacement?
I have a suspicion the real problem is with binding which is likely not correctly initialized. There's bound to be more compiler messages about that.
It could be because Boost Bind stopped putting the _1 placeholders in the global namespace by default. You might detect this by adding -DBOOST_BIND_GLOBAL_PLACEHOLDERS to the compiler flags. However, heed the advice from the code:
BOOST_PRAGMA_MESSAGE(
"The practice of declaring the Bind placeholders (_1, _2, ...) "
"in the global namespace is deprecated. Please use "
"<boost/bind/bind.hpp> + using namespace boost::placeholders, "
"or define BOOST_BIND_GLOBAL_PLACEHOLDERS to retain the current behavior."
)
Minimal repro
See if you can reproduce with this minimal reproducer (I can't but I don't have access to the requisite versions ofr MSVC/Boost):
Live ON Coliru - GCC
Live On Rextester - MSVC
#include <algorithm>
#include <iostream>
#include <list>
#include <boost/bind/bind.hpp>
using namespace boost::placeholders;
#include <boost/intrusive_ptr.hpp>
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
struct Scope {};
struct Change {};
namespace MyLib {
struct IProcessChangeObserver
: boost::intrusive_ref_counter<IProcessChangeObserver>
{
virtual ~IProcessChangeObserver() = default;
virtual void notify(Scope, Change) = 0;
};
struct Obs1 : IProcessChangeObserver {
void notify(Scope, Change) override { std::cout << "Obs1\n"; }
};
struct Obs2 : IProcessChangeObserver {
void notify(Scope, Change) override { std::cout << "Obs2\n"; }
};
}
using ObserverPtr = boost::intrusive_ptr<MyLib::IProcessChangeObserver>;
int main() {
using namespace MyLib;
std::list<ObserverPtr> observers {
new Obs1(), new Obs2(), new Obs1(),
};
Scope m_scope;
Change change;
auto binding = boost::bind(&IProcessChangeObserver::notify, _1, m_scope, change);
std::for_each(observers.begin(), observers.end(), binding);
}
Prints
Obs1
Obs2
Obs1
The actual fix was just to change _1 to std::placeholders::_1
The following code piece does not compile for me:
#include <iostream>
#include <boost/thread.hpp>
int main(int argc, char* argv[])
{
boost::thread thread(
[]() {
std::cout<<"hello";
}
);
}
With the error :
no matching function for call to ‘boost::thread::thread(main(int, char**)::<lambda()>)’
I feel like I am making a very stupid mistake here, but it has been sometime, and i still fail to find it.
You need to capture io_service by reference to get the above code snippet to compile:
void start_thread(boost::asio::io_service &io_service)
{
boost::thread tcp_thread(
[&io_service]() { // <-- you missed a & here
io_service.run();
}
);
}
Note that the io_service does not implement copy semantics.
Using Visual Studio 2013 RC and C++, I'm trying to pass an std::unique_ptr to a function that has been bound using std::bind. However, I'm having trouble because VS doesn't seem to like it when I try this. Here's what I'm trying to compile:
#include <memory>
#include <iostream>
#include <functional>
void func(std::unique_ptr<int> arg)
{
std::cout << *arg << std::endl;
}
int main()
{
std::function<void (std::unique_ptr<int>)> bound =
std::bind(&func, std::placeholders::_1);
std::unique_ptr<int> ptr(new int(42));
bound(std::move(ptr));
return 0;
}
This compiles in GCC 4.8.1, but not in VS2013 RC. I've always had problems with move semantics in VS, but I'd really like to use std::unique_ptr instead of std::shared_ptr or raw pointers.
One workaround I've found is to change the function signature to accept an std::unique_ptr&, which does compile in VS and GCC, but doesn't make the intent of func taking ownership of the std::unique_ptr particularly clear, and also prevents me from safely asynchronously calling the function unless I do something particularly ugly:
#include <memory>
#include <iostream>
#include <functional>
#include <future>
#include <string>
void func(std::unique_ptr<int>& arg)
{
std::cout << *arg << std::endl;
}
int main()
{
std::function<void (std::unique_ptr<int>&)> bound =
std::bind(&func, std::placeholders::_1);
std::unique_ptr<int> ptr(new int(42));
std::promise<void> prom;
std::async(
[&bound, &ptr, &prom]
{
std::unique_ptr<int> movedPtr = std::move(ptr);
prom.set_value();
bound(std::move(movedPtr));
});
prom.get_future().wait();
// Wait here
std::string dummy;
std::cin >> dummy;
}
Is there a way to get around this without changing func's signature?
Thanks!
I had the same problem with VS 2012 recently. I believe this is a bug in MSVC; at least in MSVC++11 the pseudo-variadic expansion seems to forward the parameters by value to some internal function. Seems this hasn't been improved.
As a workaround, I'm using lambdas instead, but another hack is required to make it work:
std::function<void (std::unique_ptr<int>)> bound =
[] (std::unique_ptr<int> arg) { func(std::move(arg)); };
still doesn't compile. But if you add any captured value (even one that isn't used), it compiles:
int x;
std::function<void (std::unique_ptr<int>)> bound =
[x] (std::unique_ptr<int> arg) { func(std::move(arg)); };
You have to move the parameter into the bound call to func also. Not only in the invocation of bound
bound(std::move(ptr));
but also in the binding:
std::function<void(std::unique_ptr<int>)> bound =
std::bind(func,
std::bind(std::move<std::unique_ptr<int>&>,
std::placeholders::_1));
This is compiling in VS2013 (update 4) for me.
Functions bound with std::bind do not forward arguments, it copies them to the function. As a result, std::bind doesn't work with move-only types as of c++11. This problem is the idea behind proposals for "more perfect forwarding" (like this one). There's a newer one, but I can't seem to find it right now.
Is it somehow possible to pass an std::unique_ptr as a parameter to a boost::thread constructor? If not, what is the best workaround?
A small example:
// errors: g++ uniqueptr_thread.cpp -std=c++0x
#include <iostream>
#include <memory>
#include <boost/thread.hpp>
class TestThread{
public:
void operator()(std::unique_ptr<int> val){
std::cout << "parameter: " << val << std::endl;
}
};
int main(int argc, char* argv[]){
std::unique_ptr<int> ptr(new int(5));
boost::thread th( new TestThread(), std::move(ptr));
}
This compiles and runs for me:
#include <iostream>
#include <memory>
#include <thread>
class TestThread{
public:
void operator()(std::unique_ptr<int> val){
std::cout << "parameter: " << *val << std::endl;
}
};
int main()
{
std::unique_ptr<int> ptr(new int(5));
std::thread th( TestThread(), std::move(ptr));
th.join();
}
But it has to be in C++0x mode. I don't know if the boost move emulation is good enough to do this or not.
A std::unique_ptr is, as the name suggests, unique. There can be only one!
Now, if your thread function takes a std::unique_ptr&&, and you use std::move to move the parameter in the thread function, then you can pass the std::unique_ptr. But then your copy will be empty, since you moved it to the other thread.
If std::move does not work, then your compiler or standard library may have bugs in it. I imagine that transferring ownership across threads like this isn't a common occurrence. And C++11 is still fairly new.
Are you sure your problem is with the unique_ptr? Why does your example use new to create your functor? That line should just read:
boost::thread th(TestThread(), std::move(ptr));