I'm trying to bypass std::packaged_task's lack of a copy constructor so that I can pass it into a std::function (which will only ever be moved).
I inherited from std::packaged_task and added a dummy copy constructor, which I assume shouldn't be called if I never copy the std::function it's moved into.
#include <iostream>
#include <future>
#include <functional>
#include <thread>
template <typename T>
class MyPackagedTask : public std::packaged_task<T()> {
public:
template <typename F>
explicit MyPackagedTask(F&& f)
: std::packaged_task<T()>(std::forward<F>(f)) {}
MyPackagedTask(MyPackagedTask&& other)
: std::packaged_task<T()>(std::move(other)) {}
MyPackagedTask(const MyPackagedTask& other) {
// Adding this borks the compile
}
};
int main()
{
MyPackagedTask<int> task([]() {return 0;});
auto future = task.get_future();
std::thread t(std::move(task));
t.join();
std::cout << future.get() << std::endl;
}
Compiling this with gcc 6.2.1 I get the following error message (just the end part, let me know if you want the whole thing...):
/usr/include/c++/6.2.1/future:1325:6: error: invalid use of void expression
(*_M_result)->_M_set((*_M_fn)());
The error message was unparseable to me, so I was wondering if I'm doing something wrong or if the compiler is failing.
The move constructor definition is not correct, it forwards std::packaged_task<T()>&& as MyPackagedTask&& and that invokes a wrong constructor of std::packaged_task<T()>. This is the cause of the compiler error you observe.
The correct one:
MyPackagedTask(MyPackagedTask&& other)
: std::packaged_task<T()>(static_cast<std::packaged_task<T()>&&>(other))
{}
In there static_cast<std::packaged_task<T()>&&>(other) does both the upcast to the base class and std::move.
Related
TestCase2 and TestCase3 can compile normally. However, in TestCase1 I get the following error:
E0312, Custom conversion from "lambda []void ()->void" to
"EventHandler" is not appropriate.
Why am I getting this error? I want to know how to solve it.
#include <functional>
#include <iostream>
class EventHandler
{
std::function<void()> _func;
public:
int id;
static int counter;
EventHandler() : id{ 0 } {}
EventHandler(const std::function<void()>& func) : _func{ func }
{
id = ++EventHandler::counter;
}
};
int EventHandler::counter = 0;
int main()
{
EventHandler TestCase1 = []() {};
EventHandler TestCase2([]() {});
EventHandler TestCase3 = static_cast<std::function<void()>>([]() {});
}
Why am I getting this error?
The lambda []() {} is not the same as std::function<void()>. That means
decltype([]() {}) != std::function<void()>
and it has to be implicitly or explicitly converted.
At the line
EventHandler TestCase1 = []() {};
copy initialization take place, where compiler first has to convert the lambda to a std::function<void()> and then a EventHandler object. Compiler can not do double implicit conventions.
Therefore, you need to be explicit here, like in TestCase3 for instance.
I want to know how to solve it.
One way is to provide a templated constructor (if you willing to)
#include <type_traits> // std::is_convertible_v
class EventHandler
{
std::function<void()> _func;
public:
template<typename Func> EventHandler(Func func)
: _func{ func }
{
static_assert(std::is_convertible_v<Func, decltype(_func)>
, "is not valid arg!");
// ....
}
// or in C++20 with <concepts> header
// template<typename Func> EventHandler(Func func)
// requires std::convertible_to<Func, decltype(_func)>
// : _func{ func }
// { ... }
};
Now you can
EventHandler TestCase1 = []() {}; // works
Demo
Case 1
Here we consider the statement:
EventHandler TestCase1 = []() {};//this is copy initialization
the above statement uses copy initialization.
And from copy initialization's documentation:
In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.
And as EventHandler can't be directly produced from the initializer lambda on the right hand side, the first case of TestCase1 isn't allowed in accordance wirh the above quoted statement.
Case 2
Here we consider the statement,
EventHandler TestCase2([]() {});//this is direct initialization
the above uses direct initialization and since there is an implicit conversion available(using the converting constructor), this time it is allowed according to the above quoted statement.
Lets say you have a variadic class with a std::tuple, that can be move constructed with args + 1 new arg. When constructed using std::apply() and a raw curly brace constructor, that constructor doesn't return an rvalue. Which means the class isn't move constructed. An example follows to clarify.
#include <cstdio>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <vector>
template <class... Args>
struct icecream {
icecream() = default;
template <class... MoreArgs>
icecream(icecream<MoreArgs...>&& ice) {
std::apply(
[this](auto&&... ds) {
data = { std::move(ds)..., {} };
},
std::move(ice.data));
}
// This works :
// template <class... MoreArgs>
// icecream(icecream<MoreArgs...>&& ice) {
// std::apply(
// [this](auto&&... ds) {
// data = { std::move(ds)...,
// std::move(std::vector<double>{}) };
// },
// std::move(ice.data));
// }
std::tuple<std::vector<Args>...> data{};
};
int main(int, char**) {
icecream<int> miam;
std::get<0>(miam.data).push_back(1);
std::get<0>(miam.data).push_back(2);
icecream<int, double> cherry_garcia{ std::move(miam) };
printf("miam : \n");
for (const auto& x : std::get<0>(miam.data)) {
printf("%d\n", x);
}
printf("\ncherry_garcia : \n");
for (const auto& x : std::get<0>(cherry_garcia.data)) {
printf("%d\n", x);
}
return 0;
}
The output is :
miam :
1
2
cherry_garcia :
1
2
The example is a little dumbed down, but illustrates the point. In the first move constructor, {} is used and the tuple copy constructs. If you uncomment the second constructor with a hardcoded std::move(), then it works.
I test on VS latest, clang latest and gcc latest. All have the same result. (wandbox : https://wandbox.org/permlink/IQqqlLcmeyOzsJHC )
So the question is, why not return an rvalue? I'm obviously missing something with the curly constructor. This might have nothing to do with the variadic stuff, but I thought I might as well show the real scenario.
Why doesn't raw curly constructor {} return an rvalue?
The problem is another.
The problem is that
data = { std::move(ds)..., {} };
call the "direct constructor" (constructor (2) in this page),
constexpr tuple( const Types&... args ); (2)
not the "converting constructor" (constructor (3))
template< class... UTypes >
constexpr tuple( UTypes&&... args ); (3)
that you expect.
The problem is that "{}" isn't enough, for the compiler, to deduce a type (the last type for UTypes... list in constructor (3)) so the constructor (3) is excluded and the compiler choose the constructor (2).
Whit constructor (2), "{}" is acceptable to construct an object of the last type of the Types... of the list because the Types... is know and not to be deduced.
But constructor (2) is a copy constructor (from the point of view of the Types... of the tuple), not a forward constructor as constructor (3), so the first vector is copied, not moved.
It's different when you call
data = { std::move(ds)..., std::move(std::vector<double>{}) };
or also
data = { std::move(ds)..., std::vector<double>{} };
because the last argument can be clearly deduced as std::vector<double>{} && so the compiler call the "converting constructor" (constructor (3)) and move the content of the first vector.
Off Topic: instead of using std::vector<double>{}, that works only when double is the last of the types in Args..., I suggest to write a more generic code using std::tuple_element.
Moreover, I suggest to SFINAE enable your constructor only when sizeof...(MoreArgs)+1u == sizeof...(Args).
Maybe also std::forward() (enabling perfect forwarding) instead of std::move() inside the lambda.
So I suggest the following constructor
template <typename ... MoreArgs,
std::enable_if_t<sizeof...(MoreArgs)+1u == sizeof...(Args)> * = nullptr>
icecream(icecream<MoreArgs...>&& ice) {
std::apply(
[this](auto && ... ds) {
data = { std::forward<decltype(ds)>(ds)...,
std::tuple_element_t<sizeof...(Args)-1u,
decltype(data)>{} };
},
std::move(ice.data));
}
In this example, a foo instance does nothing but print whether it's copy- or move-constructed.
#include <iostream>
#include <algorithm>
#include <vector>
struct foo {
foo()=default;
foo(foo &&) { std::cout << "move constructed\n"; }
foo(const foo &) { std::cout << "copy constructed\n"; }
};
int main()
{
foo x;
std::vector<int> v; // empty
std::remove_if(v.begin(), v.end(),
[x=std::move(x)](int i){ return false; });
}
This produces the following output:
move constructed
copy constructed
move constructed
move constructed
copy constructed
copy constructed
Questions:
Why does std::remove_if create so many closures ?
Even if multiple intermediate instances are necessary, one would expect they are all rvalues; so why are some of them copy-constructed ?
Compiler is gcc 8.1.1
If we take a look at the implementation of std::remove_if in gcc's libstdc++-v3 we notice that the predicate is passed down the call chain (by value, at times) a few steps before reaching the lowermost __find_if function (used by remove_if).
Let's count the moves and copies:
move constructed when the predicate (including the captured x) is sent by value, but as a non-lvalue, to std::remove_if entry point
copy constructed when passed on to the __gnu_cxx::__ops::__pred_iter(...) function, which in turn:
invokes the _GLIBCXX_MOVE macro, thus the move constructed,
which moves the predicate over to the _Iter_pred ctor which moves it (move constructed) into the _M_pred member.
The call from std::remove_if to std::__remove_if seems to be optimized, as the _Iter_pred is not an lvalue, I guess, but __remove_if in turn pass on the wrapped predicate, by value, to std::__find_if, for another copy constructed invocation.
std::__find_if, in turn, forwards the wrapped predicate, by value, to another __find_if overload, which is finally the sink of this call chain, and the final copy constructed.
It can be interesting to compare with e.g. clang's implementation of std::remove_if, as clang (6.0.1) do not produce this move-copy chain for OP's std::remove_if example. A quick glance shows that It seems as if clang use traits on the predicates type to make sure to pass the predicate as an lvalue reference.
Both clang and gcc produce the same move/copy chains for the contrived example that follows, which shows a similar chain to gcc's implementation:
#include <iostream>
#include <utility>
struct foo {
foo() = default;
foo(foo &&) { std::cout << "move constructed\n"; }
foo(const foo &) { std::cout << "copy constructed\n"; }
};
template <typename Pred>
struct IterPred {
Pred m_pred;
explicit IterPred(Pred pred) : m_pred(std::move(pred)) {}
};
template <typename T>
inline IterPred<T> wrap_in_iterpred (T l) {
return IterPred<T>(std::move(l));
}
template <typename T>
void find_if_overload(T l) {
(void)l;
}
template <typename T>
void find_if_entrypoint(T l) {
find_if_overload(l);
}
template <typename T>
void remove_if_entrypoint(T l) {
find_if_entrypoint(
wrap_in_iterpred(l));
}
int main()
{
foo x;
remove_if_entrypoint([x=std::move(x)](int){ return false; });
}
Where both gcc (8.2.0) and clang (6.0.1) produces the following chain:
move constructed
copy constructed
move constructed
move constructed
copy constructed
I'm trying to implement a class, say Foo, which follows RAII, and objects of the class are returned to the client by value, i.e.
class SomeClass {
public:
class Foo {
public:
~Foo() { /* follow raii */ }
private:
friend class SomeClass;
Foo() { /* follow raii */ }
};
Foo getFoo() { return Foo(); }
};
My immediate question would be is there any way to be sure that only one object of type Foo is constructed when calling SomeClass::getFoo()? I would think that most compilers know only one object need be constructed, but I know this is not guaranteed in most cases. Is there a better approach I can take?
I've tried returning a boost::shared_ptr<Foo> and just allocating a Foo object when constructing the shared pointer, and this works nicely. However, it does not seem ideal, as it requires heap allocation and makes for a less-clean interface.
Thanks!
Clarification
Visual Studio 2005 compiler so I don't think R-val references and C++11 related features are available.
You've taken the best approach. The copy (or in fact move in C++11) will almost surely be elided by the compiler. In fact, even the copy from the return value to some object in the calling code will probably be elided too. So this will only call a single constructor:
Foo foo = sc.getFoo();
The rule that allows both of these copies (or moves) to be elided is:
when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move
boost::optional + boost::in_place
If copy constructor is dangerous, it is better to disable it completely.
Though most of compilers would elide copies in your case, some times it is possible to disable copy elision, for instance -fno-elide-constructors - and if code which "believes" in copy-elision would happen to run on such settings - there may be fireworks.
In C++98 you may use boost::optional + boost::in_place - there is no heap allocation, becuase boost::optional reserves enough place. And it is guaranteed that there will be no any copies.
live demo
#include <boost/utility/in_place_factory.hpp>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <iostream>
#include <ostream>
using namespace boost;
using namespace std;
struct Foo: private noncopyable
{
explicit Foo(int i)
{
cout << "construction i=" << i << endl;
}
};
void make(optional<Foo> &foo)
{
foo = in_place(11);
}
int main()
{
optional<Foo> foo;
cout << "*" << endl;
make(foo);
cout << "!" << endl;
}
Output is:
*
construction i=11
!
This code does work on MSVC2005.
Boost.Move
Another option is to use move semantic emulation for C++98 - Boost.Move. Copies are disabled:
live demo
#include <boost/move/utility.hpp>
#include <iostream>
#include <ostream>
using namespace std;
class Movable
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(Movable)
bool own_resource;
public:
Movable()
: own_resource(true)
{}
~Movable()
{
cout << (own_resource ? "owner" : "empty") << endl;
}
Movable(BOOST_RV_REF(Movable) x)
: own_resource(x.own_resource)
{
x.own_resource = false;
}
Movable& operator=(BOOST_RV_REF(Movable) x)
{
own_resource = x.own_resource;
x.own_resource = false;
return *this;
}
};
Movable make()
{
return Movable();
}
int main()
{
Movable m = make();
}
Output is:
empty
empty
owner
This code also does work on MSVC2005.
C++11
In C++11 use following approach:
live demo
struct Foo
{
Foo(const Foo &)=delete;
Foo(Foo &&)=delete;
Foo &operator=(const Foo&)=delete;
Foo &operator=(Foo &&)=delete;
Foo(int){}
};
Foo create()
{
//return Foo{0}; // ERROR: needs Foo(self &&)
return {0};
}
int main()
{
auto &&t=create();
}
Foo is created only once, it's copy and move constructor are deleted - it is guaranteed that there will be no any copies or moves.
The following code compiles with clang 3.0/libc++:
#include <memory>
class Foo
{
public:
Foo()
: mem_(new int(10))
{
}
std::unique_ptr<int> mem_;
};
int main()
{
auto foo = std::make_shared<Foo>();
return 0;
}
But this one doesn't (std::string parameter added):
#include <memory>
#include <string>
class Foo
{
public:
Foo(const std::string& s)
: mem_(new int(10))
{
}
std::unique_ptr<int> mem_;
};
int main()
{
auto foo = std::make_shared<Foo>("aaa");
return 0;
}
Clang complains about the usage of a deleted constructor. To me, this makes no sense, since std::make_shared isn't supposed to copy the Foo instance, the only thing that would trigger the call to the (deleted) copy constructor of std::unique_ptr.
But lo and behold, as soon as I define a move constructor explicitly, it compiles.
#include <memory>
#include <string>
class Foo
{
public:
Foo(const std::string& s)
: mem_(new int(10))
{
}
Foo(Foo&& other)
: mem_(std::move(other.mem_))
{
}
std::unique_ptr<int> mem_;
};
int main()
{
auto foo = std::make_shared<Foo>("aaa");
return 0;
}
Now, questions:
Why does it compile in the first example but not the second?
Can std::make_shared copy/move the object while constructing it?
Why does adding a move constructor fix the problem? I don't recall that adding non-default constructor should suppress an implicit move constructor.
EDIT: Checked and all examples appear to compile fine with gcc 4.5.1 (via ideone.com), I suspect it's the case of a clang/libc++ bug, but questions 2 and 3 still stand, plus I'd like to know which compiler is more "correct".
Why does it compile in the first example but not the second?
This is a libc++ bug. I am working on a fix for it now...
Can std::make_shared copy/move the object while constructing it?
No, I don't believe it can.
Why does adding a move constructor fix the problem? I don't recall
that adding non-default constructor should suppress an implicit move
constructor.
In the version of clang you're using, implicit move constructors are not implemented yet.
Update
Fixed: http://llvm.org/bugs/show_bug.cgi?id=11616