17

In the Boost.asio C++11 examples there are snippets like the following:

void do_read() { auto self(shared_from_this()); socket_.async_read_some(boost::asio::buffer(data_, max_length), [this, self](boost::system::error_code ec, std::size_t length) { if (!ec) { do_write(length); } }); } 

I understand why the self pointer is needed to keep the class alive (see this question), but I don't understand why the this pointer is also captured. Is it just so that the author can write do_write(length) instead of self->do_write(length) or is there another reason?

1
  • 2
    In a word: convenience. Commented Jan 11, 2016 at 13:00

2 Answers 2

6

Without this captured, you cannot call methods of the class from inside the lambda (e. g. do_write). Or access member variables. Granted, you could instead write self->do_write(), but it's both less elegant and potentially slower (because of the shared_ptr involved).

Sign up to request clarification or add additional context in comments.

9 Comments

Just to expand on the speed issue: answers from this question seem to indicate that on old/bad compilers dereferencing a smart pointer may be slower that dereferencing raw pointers, but there should be almost no penalty on modern compilers.
@dshepherd: fair enough, but it's probably still slower with optimizations disabled (e. g. debug mode).
@shep I dunno: this is a const pointer to an easy to determine object. The shared ptr is constructed from a weak ptr stored in the objecr, initialized the first time a shared ptr was created from the object. I cannot imagine that there aren't cases where the optimizer has issues with that, let alone the fact that shared from this can be null!
I've found the need to capture this in order to call class-methods to work around older (and presumably buggy) versions of GCC. The code compiled just fine without using Clang.
@Yakk Do you mean shared_ptr can be nullptr? Since shared_from_this is an inherited member function that cannot possibly be called (without error) from a valid function already contained managed by a shared_ptr.
|
4

The answer given up there is ABSOLUTELY wrong! You should not pass both! Here's how you should do it, based on your code, without passing this:

void do_read() { auto self(shared_from_this()); socket_.async_read_some(boost::asio::buffer(data_, max_length), [self](boost::system::error_code ec, std::size_t length) { if (!ec) { self->do_write(length); } }); } 

8 Comments

Violet Giraffe's answer seems to makes complete sense to me. Could you elaborate on how it is wrong, and why yours is better?
@Quentin Quoting "Without this captured, you cannot call methods of the class from inside the lambda". This is purely wrong. self can do exactly what this does. Also it's wrong to assume that shared_from_this is slower (although he said "potentially", which is a useless, defensive, fluidic answer). operator-> doesn't do any checks, so the least optimization will kill any difference in performance. That answer doesn't give any useful information, but wrong information based on assumptions and generalizations. Sorry for being harsh, but I'm surprised.
Yes, I know how that works. But the question was "why was this captured", and the answer is "only for looks". If you wan't direct member access, you must capture this, and that's it.
@FloWil Nope. I don't use bind anymore.
While I think that 'absolutely' wrong is perhaps a bit more strongly worded than is warranted, I do think it's wrong from a resource perspective. That is, we're capturing this from a purely stylistic perspective; it does nothing that self can't do. However, there's zero overhead these days to self->, but there's certainly overhead to redundantly capturing this. If one observes the allocation performed by the handler allocator here, it'll likely be the size of a pointer larger with this captured. Presumably with an ASIO server one is looking for go-fast, low overhead, so there's that.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.