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]:

f callable (20.9.12.2) argument types argtypes... , return type r.

where, [func.wrap.func]:

a callable object f of type f callable argument types argtypes , return type r if expression invoke (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)) if r cv void, otherwise invoke(f, t1, t2, ..., tn) implicitly converted r.

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

Popular posts from this blog

1111. appearing after print sequence - php -

java - WARN : org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/board/] in DispatcherServlet with name 'appServlet' -

Ruby on Rails, ActiveRecord, Postgres, UTF-8 and ASCII-8BIT encodings -