I am trying to come up with the most efficient (i.e. minimal amount of copies) implementation of the following. I have a queue which is used to execute std::function<void()> objects at some later point in time. The queue can only take trivial data types and thus I need to pass it a pointer to a std::function rather than the std::function itself (i.e. the queue holds std::function<void()>* types).
Ideally, if a piece of data is captured (by value) in a lambda, only a SINGLE copy of this data should be made throughout the process of creating an std::function and adding it to the queue.
Here is an example I have been playing with:
std::function<void()>* invoke(const std::function<void()>& fn) {
printf("invoke()\r\n");
return new std::function<void()>(fn);
}
which I would use like so
class Base {
public:
virtual void sayHello() const = 0;
};
class A : public Base {
public:
A() {
printf("A::A()\r\n");
}
A(const A& a) {
printf("A copy constructor\r\n");
}
A(const A&& a) {
printf("A const move constructor\r\n");
}
A(A&& a) {
printf("A move constructor\r\n");
}
A& operator=(A&& other)
{
printf("A move assignment operator\r\n");
return other;
}
void sayHello() const override { printf("A says hello\r\n"); }
};
int main() {
A myA;
printf("invoking lambda which calls myA.sayHello()\r\n");
std::function<void()> *fn = invoke([myA](){
myA.sayHello();
});
return 0;
}
Since the lambda is capturing the object (myA) by value, a copy is made when the lambda is originally created. Now, since the lambda you see in main() is "temporary" (only used in the call to invoke) there should really only ever by a single copy of the lambda hanging around and thus only a single (additional) copy of myA.
However, here is an example of my output:
invoking lambda which calls myA.sayHello()
A copy constructor
A move constructor
invoke()
A copy constructor
It appears that, when I create a new std::function on the heap, it is COPYING the lambda (and thus myA) instead of just moving it, which is what my desired behavior is since the original lambda and std::function (the one created automatically when passing the lambda to the invoke function) are only temporary anyways.
I feel like I am very close, but am misunderstanding something here. Could anyone help?
Thanks!
EDIT
Based upon all the discussion here, I have made a few modifications to my code. Now I am stepping this up to a more complicated example as follows:
//Same A and Base classes as above
inline static void invoke(std::function<void()> fn) {
printf("invoke(std::function<void()> fn)\r\n");
std::function<void()>* newF = new std::function<void()>(std::move(fn));
(*newF)();
delete newF;
printf("return\r\n");
}
int main() {
printf("Starting Tests...\r\n");
A myA;
invoke([myA](){
myA.sayHello();
});
return 0;
}
Which has the following, unexpected output:
Starting Tests...
A::A()
A copy constructor
A move constructor
invoke(std::function<void()> fn)
A says hello
A::~A()
return
A::~A()
A::~A()
I can't figure out why there is a 3rd call to the destructor since only 2 copies of the A object should be in existence (the original copy in main() and the copy made by the copy constructor in the lambda).
Your example does not work because you are trying to std::move from a const reference. This will result in a type std::function<...> const&&, but the move constructor of std::function only accepts std::function<...>&& (without the const). This is not unusual in C++, as const rvalue references are a weird corner case of the language that don't make much sense conceptually. In particular, you cannot reasonably move from a const rvalue reference, because you won't be allowed to make any changes to the source.
If the intention is to guarantee that no copies happen, you should accept the argument via rvalue reference:
std::function<void()>* invoke(std::function<void()>&& fn) {
printf("invoke()\r\n");
return new std::function<void()>(std::move(fn));
}
Note that this restricts the function to only work with rvalue arguments. If you prefer a more flexible design, consider max66's answer.
Maybe... using perfect forwarding you can transform a copy in a move.
template <typename F>
auto invoke (F && fn) {
printf("invoke()\r\n");
return new std::function<void()>(std::forward<F>(fn));
}
You get
A::A()
invoking lambda which calls myA.sayHello()
A copy constructor
invoke()
A move constructor
A move constructor
Unrequested Suggestion: avoid like the plague direct memory allocation management; use smart pointer instead
template <typename F>
auto invoke (F && fn) {
printf("invoke()\r\n");
return std::unique_ptr<std::function<void()>>
{new std::function<void()>(std::forward<F>(fn))};
}
Related
Can anyone explain why the copy constructor here is called two times?
class A
{
int i;
public:
A(){cout<<"IN constr"<<endl;};
A(int x):i(x) {};
A (A &a)
{
cout<<"in copy"<<endl;
i= a.i;
}
};
class MyClass {
A var;
public:
MyClass(A a):var(a) {
}
};
int main() {
A a1;
MyClass m(a1);
return 0;
}
When i run the code out put is:
IN constr
in copy
in copy
I can understand one time when it copies a into the variable var, but when it gets called second time?
You are passing the constructor argument by value, which is where your second copy comes from. You'll get just one copy if you change the constructor signature to the more canonical C++:
MyClass(const A& a)
: var(a)
{
}
That's called argument passing by const reference, and pre-C++11 it was basically the go-to way of passing arguments to functions.
If you know you will be dealing with temporary objects passed as function arguments though, then C++11 and onwards also have pass-by-rvalue-reference - see e.g. Pass by value vs pass by rvalue reference for more information.
The first copy is from a1 to the parameter a of the MyClass constructor, the second one is from the parameter a to the member var.
If you want to reduce the number of copies, you have (at least) two options:
Pass a const reference to the constructor as mentioned by Joris:
MyClass(A const &a) : var(a) {
}
If A can be efficiently moved, take a by value and move to the member:
MyClass(A a) : var(std::move(a)) {
}
That way, a user that does not need his A anymore can move it into the new MyClass instance, while a user that still needs the A can pass it by value.
void useA(A &a);
void doSomethingWithM(MyClass & m);
void functionThatNeedsAAgain() {
A myImportantA;
MyClass m {myImportantA}; // copy myImportantA once
useA(myImportantA);
doSomethingWithM(m);
}
void functionThatDoesNotNeedAAgain() {
A tempA;
// no copy needed, as tempA will never be used again
MyClass m {std::move(tempA);
doSomethingWithM(m);
}
The third option would be to provide constructors from both const A& and A&& but I would weigh the code duplication against the benefit.
If you want to know how far this can be taken if A happens to be std::string and you want to cover the construction of temporary As, watch this excellent talk by Nicolai Josuttis.
Let's say I have Foo class:
struct Resource {
void block();
void unblock();
};
struct Foo {
static Foo create() {
Resource resource;
resource.block();
return Foo{resource};
}
~Foo() { resource.unblock(); }
void f() {}
private:
Resource resource;
Foo(Resource resource): resource(resource) {}
};
Am I right and there is no guarantee that ~Foo will be called only once in such block?
{
Foo foo = Foo::create();
foo.f();
}
If there is no guarantee, is it possible to fix somehow if using c++11 and move semantic? For example not call unblock_resource in moved foo, but I am not sure is there guarantee to use move constructor/operator= in return from Foo::create?
Copy elision won't help you, since it is an optimization and may or may not be applied.
Move semantics do help, and you get guaranteed moves in function return of local variables. But that means you have to write the move constructor, and you have to modify the destructor so that it doesn't unlock the resource of an object that was moved from.
Not sure about how this is related to the factory pattern, but to answer your question "Am I right and there is no guarantee that ~Foo will be called only once in such block?":
Avoiding copying/moving objects used as return values (i.e. return value optimization, especially named return value optimization) is permitted, but not guaranteed:
Under the following circumstances, the compilers are permitted, but
not required to omit the copy- and move- (since C++11)construction of
class objects even if the copy/move (since C++11) constructor and the
destructor have observable side-effects. This is an optimization: even
when it takes place and the copy-/move-constructor is not called, it
still must be present and accessible (as if no optimization happened
at all), otherwise the program is ill-formed:
If a function returns a class type by value, and the return
statement's expression is the name of a non-volatile object with
automatic storage duration, which isn't a function parameter, or a
catch clause parameter, and which has the same type (ignoring
top-level cv-qualification) as the return type of the function, then
copy/move (since C++11) is omitted. When that local object is
constructed, it is constructed directly in the storage where the
function's return value would otherwise be moved or copied to. This
variant of copy elision is known as NRVO, "named return value
optimization".
One way could be to control locking/unlocking resources in the move constructor and the destructor, just as you mentioned in your question.
Another way could be to make use of shared_ptr, such that creation and deletion of your Foo-object is managed by an RAII-style shared_ptr wrapper. There is just one tricky thing if you want to keep the Foo-constructor private, since make_shared cannot deal with private constructors. To overcome this, you could declare a public constructor taking a parameter of a private data type as parameter. A little bit ugly, and maybe a little bit clumsy due to the shared_ptr-wrapper. But maybe it's at least some inspiration:
struct Foo {
private:
struct private_dummy {};
public:
static shared_ptr<Foo> create() {
shared_ptr<Foo> foo = make_shared<Foo>(private_dummy{});
return foo;
}
~Foo() { cout << "deleted."; }
Foo(struct private_dummy x) { cout << "created."; }
};
void test() {
shared_ptr<Foo> foo = Foo::create();
}
int main() {
test();
//Foo notOK();
}
Rule of 3/5/0. You define a destructor, but not copy / move constructors / assignment operators, which is a red flag that your type is unsafe. Indeed, the destructor may get called twice prior to C++17, and it's easy to mess up while using it even post C++17.
I recommend using std::unique_ptr so that you don't define any copy/move operations or the destructor. You can use std::unique_ptr even if the resource you are managing isn't a pointer; it'd look something like this:
class Resource {
int handle;
public:
Resource(std::nullptr_t = nullptr)
: handle{}
{}
Resource(int handle)
: handle{ handle }
{}
explicit operator bool() const { return handle != 0; }
friend bool operator==(Resource lhs, Resource rhs) { return lhs.handle == rhs.handle; }
friend bool operator!=(Resource lhs, Resource rhs) { return !(lhs == rhs); }
void block() { std::cout << "block\n"; }
void unblock() { std::cout << "unblock\n"; }
struct Deleter {
using pointer = Resource;
void operator()(Resource resource) const {
resource.unblock();
}
};
};
struct Foo {
static Foo create() {
Resource resource{42};
resource.block();
return Foo{resource};
}
void f() {}
private:
std::unique_ptr<Resource, Resource::Deleter> resource;
Foo(Resource resource): resource(resource) {}
};
You are looking for copy-elision.
In short, your code is guaranteed to work in C++17, as described at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html
In C++14 and before there is no such guarantee.
Copy elision is an optimization that existed before C++11 and allowed compiler to omit copy constructor call in some cases.
C++11 has added move semantics and copy elision was expanded to allow compiler to avoid moving or copying (if moving is not available) an object.
Regardless of what compiler actually does, your class must still provide copy or move constructor, even if one will not be used by the compiler.
C++17 introduces "guaranteed copy-elision", which allows you to return objects of non-movable classes, just like in your case. Note that proposal explicitly mentions "factory functions". Quote:
it is impossible or very difficult to write factory functions
Example from proposal has this example:
struct NonMoveable {
NonMoveable(int);
NonMoveable(NonMoveable&) = delete;
void NonMoveable(NonMoveable&) = delete;
std::array<int, 1024> arr;
};
NonMoveable make() {
return NonMoveable(42); // ok, directly constructs returned object
}
As of today, both Clang and GCC are able to compile that code with -std=c++17 flag, but not with -std=c++14.
I see two ways for you to solve this problem:
Use C++17: I recommend deleting both copy and move constructor (and operator=) to make sure your code will not compile under earlier standard with buggy effects.
Rely only on things that are available in C++14 to make your code work everywhere. You might want add additional state to your object, delete copy constructor and implement move constructor.
This is an example of how it can be done in C++14.
class Foo {
public:
Foo() = default;
Foo(const Foo &) = delete;
Foo(Foo &&rvalue) noexcept { std::swap(blocked, rvalue.blocked); }
~Foo() { if (blocked) unblock();
void block() { blocked = true; }
void unblock() { blocked = false; }
private:
bool blocked{false};
};
About std::move, here is what I can interpret, according to http://en.cppreference.com/w/cpp/utility/move :-
If I want to transfer ownership, I have to call std::move (or in rare case, std::forward).
Responsibility of std::move is calling operator=(A&& other).
The most essential step of the move operation is supposed to be implemented in operator=(A&&).
It is tricky to ensure that operator=(A&&) would be called. It need a special converter.
There are only two converters in the C++ world that can convert variables into xvalue (the &&) : std::move and std::forward.
Question
After adding many of std::move(std::unique_ptr) in my code, I start to worry that for such basic feature like transfer ownership, I have to heavily rely on the standard library (std::).
Do I really have to use std::move to transfer ownership?
Is spamming and hard-code calling std::move in many places of code-base a correct way to go for a high-standard program?
Should std::move be encapsulated?
They are actually a single question, but ask in different perspectives.
Edit
As request, here is my trial & error. It compiled ok.
I have no problem about the code, but I worry about its approach / pattern.
https://ideone.com/y8Pcgf
class T{
public: int value;
public: T(int a=1234){
value = a;
}
};
int main() {
std::unique_ptr<T> t1 = std::unique_ptr<T>(new T(1));
void* databaseNew=operator new [](sizeof(std::unique_ptr<T>));
std::unique_ptr<T>* t1ptr=static_cast<std::unique_ptr<T>*>(databaseNew);
new (t1ptr) std::unique_ptr<T>(std::move(t1));
return 0;
}
Rule of thumb:
If you're in a deduced x-value context, use std::forward:
template<class T>
void foo(T&& t) // T is deduced x-value, so we forward it
{
bar(std::forward<T>(t));
}
Otherwise use std::move
template<class T>
void foo1(std::vector<T> v) // although vector<T> is deduced, it's not an x-value
{
bar(std::move(v)); // so move it
}
template<class T>
void foo2(std::vector<T>&& v) // although vector<T> is deduced, it's not an x-value.
// In this case an r-value reference
{
bar(std::move(v)); // so move it
}
template<class T>
void foo3(std::vector<T>& v) // although vector<T> is deduced, it's not an x-value.
// In this case an l-value reference
{
bar(std::move(v)); // so move it
}
void foo4(std::vector<int> v) // complete type
{
bar(std::move(v)); // so move it
}
void foo5(std::vector<int> const & v) // const reference
{
bar(v); // not much point in moving it. std::move would cast it
// to std::vector<int> const&&, which although is detectable
// decays to std::vector<int> const&
}
which although is detectable... what?
It is permissible, if not necessarily advisable to write code like this:
#include <iostream>
struct X
{
void foo() const &
{
// do one thing...
std::cout << "one thing\n";
}
void foo() const &&
{
// do something else...
std::cout << "or another\n";
}
};
int main()
{
const X x;
x.foo();
std::move(x).foo();
}
const r-value references do exist, it's just that no-one uses them because there is no reasonable use-case.
The need to explicitly move, of which you complain, was actually done on purpose. Before unique_ptr, STL had a horrid construct called auto_ptr. It would move ownership impllicitly, and was borderline unusable unless you really really really knew what you were doing.
To make things more usable, in most cases C++ now requires you to explicitly state that you intend on moving ownership over a container, by using std::move.
In fact, std::move is little more than a cast to an rvalue reference.
There are cases where such an explicit specification is not necessary. For example, if the container from which you take ownership is already an rvalue (e.g. - a temporary object), then no case using std::move is necessary. For example, the following doesn't compile:
std::unique_ptr<int> a;
a = new int;
But the following does, without needing a move:
std::unique_ptr<int> a;
a = std::unique_ptr<int>(new int);
The reason this does not need a call to std::move, despite invoking the move operator, is that the object we move the ownership away from is already a temporary object (i.e. - an rvalue), so no cast is necessary.
Another example is if you call a function that returns a unique_ptr. You might have to call std::move inside the function to get it into the return value, but you do not need to call std::move on the function's return value to get it into the outside unique_ptr. It is already an rvalue, and therefor no cast is necessary.
Assume I have a non-copyable class with multiple constructors with like this
class Foo: boost::noncopyable
{
public:
Foo(std::string s) {...}; // construct one way
Foo(int i) {...}; // construct another way
}
Now, I want to construct an object, and choose which constructor to use at runtime:
I could do it with pointers like this:-
boost::shared_ptr<Foo> f;
if (condition)
f.reset(new Foo(myString));
else
f.reset(new Foo(myInteger));
// common code follows
f->doSomethingComplicated(...);
But that feels messy and slow. Is there an easy way to choose the constructor for the object without resorting to dynamic allocation?
Some more details : The Foo class above is simply to illustrate the problem.The actual class involved is Windows Gdiplus::Bitmap - http://msdn.microsoft.com/en-gb/library/windows/desktop/ms534420(v=vs.85).aspx
You can do it with C++11 on stack, without placement new and without copy/move constructor/assignment available. Observe:
auto factory = [&]() -> Foo
{
if (condition) {
return { myString };
} else {
return { myInteger };
}
};
Foo&& foo = factory();
foo.doSomethingComplicated();
The functor and the Foo instance will live happily on stack, no allocations made (except for copying string in Foo's constructor, probably). Foo will get its destructor called when it gets out of scope. Win.
When using uniform initialization to construct return value, no copy/move operation is involved. Note that returning myString (implicit conversion) or Foo(myString) would force compiler to check if object is copyable/moveable, even if such copy/move could be elided.
Edit: alternatively, this can be made even shorter, but bit more "magical":
Foo&& foo = [&]() -> Foo
{
if (condition) {
return { myString };
} else {
return { myInteger };
}
}();
Edit: Pre-C++11, Visual Studio hacky solution:
VC doesn't seem to check whether object is copyable when resorting on implicit conversion constructors to return value from a function. So this is valid, even though it's against the standard:
Foo make_foo(bool condition, const std::string&s, int i)
{
if ( condition) {
return s;
} else {
return i;
}
}
Then just use it like that:
Foo& f = make_foo(condition, myString, myInteger);
Note that this is yet another VC hack, as according to standard temporary can't be assigned to a reference to a mutable object, i.e. it would need to be changed const Foo&, which would be quite limiting here.
Not saying that you should handle it this way, but it is possible.
You have a flaw in your design. The 'Foo' is delegating the type elision to the user of the class. Have a look at boost::any (http://www.boost.org/doc/libs/1_55_0/doc/html/any.html)
I think the best option that meets your requirements (not dynamically allocated, not-copyable, pre-C++11) would be to use the placement new.
See here for a short example.
boost::optional might also be an acceptable option for you (it basically just does this for you internally, as well as keeping track of whether the object has been initialized). The in-place construction is a bit messy though for optional imo.
Keep it small and simple, I'd say. If this is a very local problem, why not just repeat the call?
if (condition)
{
Foo f(myString);
f.doSomethingComplicated();
}
else
{
Foo f(myInt);
f.doSomethingComplicated();
}
If that does not prove feasible, wrap a Foo pointer (or smart pointer) in a new class.
class FooWrapper // copyable
{
private:
boost::shared_ptr<Foo> m_foo;
public:
FooWrapper(std::string const &s) : m_foo(new Foo(s)) {}
FooWrapper(int i) : m_foo(new Foo(i)) {}
void doSomethingComplicated() { m_foo->doSomethingComplicated(); }
};
FooWrapper foo = condition ? FooWrapper(myString) : FooWrapper(myInt);
foo.doSomethingComplicated();
Using C++11 you can do:
Foo&& f = condition ? Foo{myInteger} : Foo{myString};
f.doSomethingComplicated();
By using an r-value reference you avoid the constness and still extend the lifetime of the temporary.
If you only need to construct a temporary object, I think you can bind it to a const reference using a ternary expression:
const Foo &f(condition ? Foo(myString) : Foo(myInteger));
f.doSomethingComplicated(...);
In C++03 it is impossible to return an object of a class having a private non-defined copy constructor by value:
struct A { A(int x) { ... } private: A(A const&); };
A f() {
return A(10); // error!
return 10; // error too!
}
I was wondering, was this restriction lifted in C++11, making it possible to write functions having a class type return type for classes without constructors used for copy or move? I remember it could be useful to allow callers of a function use the newly returned object, but that they are not able to copy the value and store it somewhere.
Here is how it can work
A f() {
return { 10 };
}
This works even though A has no working copy or move constructor and no other constructor that could copy or move an A!
To make use of this feature of C++11, the constructor (taking int in this case) has to be non-explicit though.
The restriction has not been lifted. As per the access specifier, there is a note in §12.8/32 that explains:
two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided.
As of the deleted copy/move constructors §8.4.3/2 states that
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. — end note ]
Not sure about this particular case, but my understanding of the quote is that, if after the overload resolution in §12.8/32 the deleted copy/move constructor is selected, even if the operation is elided, that could constitute a reference to the function, and the program would be ill formed.
The above code is still ill-formed in C++11. But you could add a public move constructor to A and then it would be legal:
struct A
{
A(int x) {}
A(A&&);
private:
A(A const&);
};
A f() {
return A(10); // Ok!
}
I was wondering, was this restriction lifted in C++11?
How could it be? By returning something by value, you are by definition copying (or moving) it. And while C++ can allow that copy/move to be elided in certain circumstances, it's still copying (or moving) by the specification.
I remember it could be useful to allow callers of a function use the returned object, but that they are not able to copy the value and store it somewhere.
Yes. You get rid of the copy constructor/assignment, but allow the value to be moved. std::unique_ptr does this.
You can return a unique_ptr by value. But in doing so, you are returning an "prvalue": a temporary that is being destroyed. Therefore, if you have a function g as such:
std::unique_ptr<SomeType> g() {...}
You can do this:
std::unique_ptr<SomeType> value = g();
But not this:
std::unique_ptr<SomeType> value1 = g();
std::unique_ptr<SomeType> value2 = g();
value1 = value 2;
But this is possible:
std::unique_ptr<SomeType> value = g();
value = g();
The second line invokes the move assignment operator on value. It will delete the old pointer and move the new pointer into it, leaving the old value empty.
In this way, you can ensure that the contents of any unique_ptr is only ever stored in one place. You can't stop them from referencing it in multiple places (via pointers to unique_ptr or whatever), but there will be at most one location in memory where the actual pointer is stored.
Removing both the copy and move constructors creates an immobile object. Where it is created is where it's values stay, forever. Movement allows you to have unique ownership, but without being immobile.
You could probably hack together a proxy to do the trick if you really wanted, and have a converting constructor that copies the value stored within the proxy.
Something along the lines of:
template<typename T>
struct ReturnProxy {
//This could be made private, provided appropriate frienship is granted
ReturnProxy(T* p_) : p(p_) { }
ReturnProxy(ReturnProxy&&) = default;
private:
//don't want these Proxies sticking around...
ReturnProxy(const ReturnProxy&) = delete;
void operator =(const ReturnProxy&) = delete;
void operator =(ReturnProxy&&) = delete;
struct SUPER_FRIENDS { typedef T GO; };
friend struct SUPER_FRIENDS::GO;
unique_ptr<T> p;
};
struct Object {
Object() : data(0) { }
//Pseudo-copy constructor
Object(ReturnProxy<Object>&& proxy)
: data(proxy.p ? proxy.p->data : throw "Don't get sneaky with me \\glare")
{
//steals `proxy.p` so that there isn't a second copy of this object floating around
//shouldn't be necessary, but some men just want to watch the world burn.
unique_ptr<Object> thief(std::move(proxy.p));
}
private:
int data;
Object(const Object&) = delete;
void operator =(const Object&) = delete;
};
ReturnProxy<Object> func() {
return ReturnProxy(new Object);
}
int main() {
Object o(func());
}
You could probably do the same in 03, though, using auto_ptrs. And it obviously doesn't prevent storage of the resultant Object, although it does limit you to one copy per instance.