<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Oct 9, 2014 at 12:11 AM, Jared Grubb <span dir="ltr"><<a href="mailto:jared.grubb@gmail.com" target="_blank">jared.grubb@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><br><div><span class=""><blockquote type="cite"><div>On Oct 3, 2014, at 14:50, David Blaikie <<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>> wrote:</div><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Oct 3, 2014 at 12:55 PM, Jared Grubb <span dir="ltr"><<a href="mailto:jared.grubb@gmail.com" target="_blank">jared.grubb@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div>I spoke with Marshall briefly about this at CppCon. My suggestion is that std::function should either:</div><div> * correctly capture blocks and just work (as this patch does)</div><div> * compile with error if you try it (and also maybe add a convenience adaptor like you suggest to allow it to manually work)</div><div><br></div><div>The current problem is that if you write something like this:</div><div>   template <typename F> doSomething(F&& functor) { std::function<...> capturing = std::forward<F>(functor); ... }</div><div>This works great for lambdas. For blocks, it compiles just fine but has runtime issues.</div></div></blockquote><div><br></div><div>What runtime issues are you referring to? Could you provide a simple standalone complete example?</div></div></div></div></div></blockquote><div><br></div></span><div><div><div><div>Here's an example.</div><div><br></div></div></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div><div><div><div><div><div>int main(int argc, const char**) {</div><div>    std::function<void()> f;</div><div><br></div><div><div>    std::vector<int> vec = {1, 2, 3};</div><div>    if (argc == 1) {</div><div>        f = ^{ std::cout << vec.size() << " (block)\n"; };</div><div>    } else {</div><div>        f = [=]{ std::cout << vec.size() << " (lambda)\n"; };</div><div>    }</div><div><br></div></div><div>    f();</div><div>}</div><div><br></div></div></div></div></div></div></div></blockquote><div>On my machine, it doesnt crash, but the block part is definitely broken:</div></div></div></div></blockquote><div><br></div><div>Fair enough.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div><div>$ ./a.out</div><div><div>0 (block)</div><div>$ ./a.out 1</div><div>3 (lambda)</div><div><br></div><div>Other examples, especially multithreaded ones, will crash and behave in undefined ways.</div></div></div></div></div></blockquote><div><br></div><div>Hmm - which kind of multithreading do you have in mind? I'm not sure why that'd be a particular problem.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><div><br></div></div><div><span class=""><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>I assume the issue is that std::function will capture the block's (presumably raw) pointer by value but do none of the increment/decrement.</div></div></div></div></blockquote><div><br></div></span><div>Yes.</div></div></div></div></div></blockquote><div><br></div><div>Would it be possible/reasonable to warn/error on copying the raw block pointer? (passing it to any function at all) std::function isn't the only entity that could cause this kind of dangling block pointer bug & it might be nicer to fix it in the language for all such cases, than fix one (albeit common/easily triggered) case in the library?<br><br>I assume I could write the same bug with something like:<br><br>T *t; // not sure what 'T' is, but I imagine it's writeable?<br>if (x) {<br>  t = ^{ std::cout << vec.size() << " (block)\n"; };<br>}<br>t();</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><span class=""><br><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>This doesn't seem necessarily broken & I'm not sure (for myself) it merits library support to protect.</div></div></div></div></blockquote><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br>This would be the same behavior as any other lifetime issues with pointer captures.<br><br>  std::function<...> func() {<br>    int i;<br>    int *j = &i;<br>    return [=j] () { ... }; // captured j by value, but it points to something that goes out of scope at the end of the function. Bad.<br>  }<br><br>But similar code isn't a problem at all:<br><br></div><div>  void func(std::function<...>); // func calls the std::function, maybe copies it around, but doesn't copy it to global storage/anywhere that outlives the <br>  ...<br>  int i;<br>  int *j = &i;<br>  func([=j]() { ... });<br></div></div></div></div></blockquote><div><br></div></span><div>You're right that it's the same "bad pointer to stack" issue, but the problem is at a different level. In the example above, the closures themselves are perfectly fine. The problem is that std::function captures the closure incorrectly. That's why I think it's a library issue.</div><span class=""><font color="#888888"><div><br></div><div>Jared</div></font></span></div></div><div><br></div></div></div></blockquote></div><br></div></div>