I've looked at cppreference.com and they seem to indicate no noexcept
specification on std::function(std::function&&)
. This seems rather odd to me. Does the standard really not give a nothrow guarantee in this case?
Quoting the standard (as you request):
C++11 §20.8.11.2.1/6 (from N3290):
function(function&& f);
template <class A> function(allocator_arg_t, const A& a, function&& f);
Effects: If!f
,*this
has no target; otherwise, move-constructs the target off
into the target of*this
, leavingf
in a valid state with an unspecified value.
So, sorry, no noexcept
on the move constructor.
There is a related Defect Report 2062 which is still open, but it goes in the other direction, so to speak, namely that there is at least one noexcept
that apparently should not be there, for whatever the rationale of that is…
It may be that the intent is to support callables that have throwing move constructors. But that is just speculation in the direction of rationalization. For example, imagine reallocation of the buffer in a vector of such function objects, where an attempt is made to move the originals, and where in the middle somewhere one of them throws (I think this was the original example by Abrahams et.al). Oh dang, they can't guaranteed be moved back, and neither can we go forward. So the reallocation fails, and the operation that caused the reallocation, fails, with the vector in an invalid state . A requirement of non-throwing move of the callable objects would have supported such general usage of function objects, including optimized vector reallocation (etc.). Which IMHO makes it doubtful that the intent really has been to make this trade-off.
None of the other answers really make sense to me. std::function
does have a noexcept
default constructor and a noexcept
swap
method, so an implementor could always define the move constructor like so:
function(function&& other) noexcept
: function()
{
swap(*this, other);
}
Given the above, I'm not sure why the committee declined to make the move constructor noexcept
. In any case, you can work around the problem by creating a wrapper to hold the std::function
and move it using this technique.
I imagine that the function
object is capable of storing an arbitrary, user-defined, callable object. When you move the function
object, that contained, user-defined object is moved as well, and there are no guarantees that this can be done without exceptions.
As others said the std::function
move constructor is NOT noexcept
by the C++ standard.
As Peter Ruderman said, an implementor can define noexcept
move constructor using swap
method (which is noexcept
by the standard).
And the GCC implementation actually uses this technique and defines the std::function
move constructor as noexcept
:
/**
* @brief %Function move constructor.
* @param __x A %function object rvalue with identical call signature.
*
* The newly-created %function contains the target of @a __x
* (if it has one).
*/
function(function&& __x) noexcept : _Function_base()
{
__x.swap(*this);
}
So if you use GCC , you can assume that the std::function
move constructor is noexcept
. But other implementation of the C++ standard library may have a different implementation of the move constructor. So you must not rely on that.
It is better to have std::function
default constructed ( noexcept
) and then use swap
method:
// the line below could throw
// std::function<void()> my_function(std::move(the_function_to_move_from));
// the code below is noexcept
std::function<void()> my_function;
my_function.swap(the_function_to_move_from);
It is not as graceful as using move constructor but at least it is portable.
And beware of move semantic!!! It may do something you don't expect because it is usually specified to leave the object moved from in a valid but unspecified state. For example:
#include <iostream>
#include <functional>
struct A
{
void call()
{
if (fn) fn();
}
std::function<void()> fn;
};
int main()
{
std::function<void()> hello = []() { std::cerr << "Hello world" << std::endl; };
A a;
hello = std::move(a.fn);
a.call(); // may print "Hello world". Is it what you expect?
return 0;
}
The GCC implementation doesn't print "Hello world" , but other implementation may do. The right way is to explicitly clear the object moved from:
hello = std::move(a.fn);
a.fn = nullptr;
But it makes move semantic inconvenient to use (IMO).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.