c++11 - Odd return behavior with std::function created from lambda (C++) -
i'm having trouble std::functions created lambdas if function returns reference return type isn't explicitly called out reference. seems std::function created fine no warnings, upon calling it, value returned when reference expected, causing things blow up. here's contrived example:
#include <iostream> #include <vector> #include <functional> int main(){ std::vector<int> v; v.push_back(123); std::function<const std::vector<int>&(const std::vector<int>&)> callback = [](const std::vector<int> &in){return in;}; std::cout << callback(v).at(0) << std::endl; return 0; } this prints out garbage, if lambda modified explicitly return const reference works fine. can understand compiler thinking lambda return-by-value without hint (when ran problem, lambda directly returning result function returned const reference, in case think const reference return of lambda deducible, apparently not.) surprised compiler lets std::function constructed lambda mismatched return types. behavior expected? missing in standard allows mismatch occur? i'm seeing g++ (gcc) 4.8.2, haven't tried else.
thanks!
why broken?
when return type of lambda deduced, reference , cv-qualifications dropped. return type of
[](const std::vector<int> &in){return in;}; is std::vector<int>, not std::vector<int> const&. result, if strip out lambda , std::function part of code, have:
std::vector<int> lambda(std::vector<int> const& in) { return in; } std::vector<int> const& callback(std::vector<int> const& in) { return lambda(in); } lambda returns temporary. copied input. temporary bound reference return in callback. temporaries bound reference in return statement not have lifetime extended, temporary destroyed @ end of return statement. thus, @ point:
callback(v).at(0) -----------^ we have dangling reference destroyed copy of v.
the solution explicitly specify return type of lambda reference:
[](const std::vector<int> &in)-> const std::vector<int>& {return in;} [](const std::vector<int> &in)-> decltype(auto) {return in;} // c++14 now there no copies, no temporaries, no dangling references, , no undefined behavior.
who's @ fault?
as whether expected behavior, answer yes. conditions constructibility of std::function [func.wrap.func.con]:
fcallable (20.9.12.2) argument typesargtypes..., return typer.
where, [func.wrap.func]:
a callable object
fof typefcallable argument typesargtypes, return typerif expressioninvoke (f, declval<argtypes>()..., r), considered unevaluated operand (clause 5), formed (20.9.2).
where, [func.require], emphasis mine:
define
invoke(f, t1, t2, ..., tn, r)static_cast<void>(invoke (f, t1, t2, ..., tn))ifrcvvoid, otherwiseinvoke(f, t1, t2, ..., tn)implicitly convertedr.
so, if had:
t func(); std::function<t const&()> wrapped(func); that meets standard requirements: invoke(func) well-formed , while returns t, t is implicitly convertible t const&. isn't gcc or clang bug. standard defect, don't see why ever want allow such construction. never valid, wording should require if r reference type f must return reference type well.
Comments
Post a Comment