Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > C++0x lambda and capturing computed values

Reply
Thread Tools

C++0x lambda and capturing computed values

 
 
Sohail Somani
Guest
Posts: n/a
 
      05-07-2009
Hello,

I'm pretty sure the answer is "no" but is it possible to capture
computed values?

Specifically, I am thinking of the following case:

vector<function<void()>> functions;

for(iterator it = ...)
{
functions.push_back(boost::bind(whatever,*it);
}

Here, the "*it" sub expression passes in a computed value to boost::bind
which is then stored by value. If I change it to the following:

for(...)
{
functions.push_back([it](){whatever(*it);});
}

This is a potential bug since the iterator can become invalidated by the
time the function is called.

The undesirable alternative is:

for(...)
{
value_type & t = *it;
functions.push_back([t](){whatever(t);});
}

It would be ideal if I could do something like:

functions.push-back([t=*it](){whatever(t);});

Any thoughts or suggestions?

Thanks in advance!

--
Sohail Somani
http://uint32t.blogspot.com
 
Reply With Quote
 
 
 
 
SG
Guest
Posts: n/a
 
      05-07-2009
On 7 Mai, 19:27, Sohail Somani <(E-Mail Removed)> wrote:
>
> vector<function<void()>> functions;
>
> for(iterator it = ...)
> {
> * functions.push_back(boost::bind(whatever,*it);
> }
>
> Here, the "*it" sub expression passes in a computed value to boost::bind
> which is then stored by value. If I change it to the following:
>
> for(...)
> {
> * functions.push_back([it](){whatever(*it);});
> }
>
> This is a potential bug since the iterator can become invalidated by the
> time the function is called.
>
> The undesirable alternative is:
>
> for(...)
> {
> * value_type & t = *it;
> * functions.push_back([t](){whatever(t);});
> }


I had to look into the draft again to check whether it actually does
what you seem to think it does due to decltype(t) being a reference.
But yes, it captures the referred-to object by value. So, inside the
lambda's body decltype(t) will not be a reference and it'll be
equivalent to what your first version with boost::bind does.

> It would be ideal if I could do something like:
>
> functions.push-back([t=*it](){whatever(t);});
>
> Any thoughts or suggestions?


Interesting idea. But it'll hardly save you typing. IMHO,

auto&& t = *it;
functions.push_back([=]{whatever(t);});

is an okay-solution which doesn't justify a more complicated grammar
in the capture clause.


Cheers!
SG
 
Reply With Quote
 
 
 
 
Sohail Somani
Guest
Posts: n/a
 
      05-07-2009
SG wrote:
> On 7 Mai, 19:27, Sohail Somani <(E-Mail Removed)> wrote:
>> The undesirable alternative is:
>>
>> for(...)
>> {
>> value_type & t = *it;
>> functions.push_back([t](){whatever(t);});
>> }

>
> I had to look into the draft again to check whether it actually does
> what you seem to think it does due to decltype(t) being a reference.
> But yes, it captures the referred-to object by value. So, inside the
> lambda's body decltype(t) will not be a reference and it'll be
> equivalent to what your first version with boost::bind does.


I had to double-check as well

Just to clarify, your understanding comes from [expr.prim.lambda]/7 ?

>> It would be ideal if I could do something like:
>>
>> functions.push-back([t=*it](){whatever(t);});
>>
>> Any thoughts or suggestions?

>
> Interesting idea. But it'll hardly save you typing. IMHO,
>
> auto&& t = *it;
> functions.push_back([=]{whatever(t);});
>
> is an okay-solution which doesn't justify a more complicated grammar
> in the capture clause.


Well the actual case is something like:

for(iterator it1, it2, it3 ...)
{
.. some stuff here ..
functions.push_back(bind(whatever,*it1,*it2,*it3)) ;
}

To me, the alternative is quite verbose.

For comparison:

for(iterator it1, it2, it3 ...)
{
auto&& t1=*it1;
auto&& t2=*it2;
auto&& t3=*it3;
functions.push_back([=](){whatever(t);});
}

or

for(iterator it1, it2, it3 ...)
{
functions.push_back([t1=*it1,t2=*it2,t3=*it3]()
{whatever(t1,t2,t3);});
}

Less typing even if it is for 6*3 characters is better if you ask me.
Seems that bind is not obsoleted by lambda (I didn't expect it to be
anyway.)

--
Sohail Somani
http://uint32t.blogspot.com
 
Reply With Quote
 
Sohail Somani
Guest
Posts: n/a
 
      05-07-2009
Sohail Somani wrote:
> for(iterator it1, it2, it3 ...)
> {
> functions.push_back([t1=*it1,t2=*it2,t3=*it3]()
> {whatever(t1,t2,t3);});
> }
>
> Less typing even if it is for 6*3 characters is better if you ask me.
> Seems that bind is not obsoleted by lambda (I didn't expect it to be
> anyway.)


What about something like:

for(...)
{
functions.push_back([](){whatever(<*it1>,<*it2>,<*it3>);}
}

I dunno... Just something to avoid all the typing would be nice. I'm
sure it's not gonna happen but this is from the result of porting an app
to use C++0x lambda where possible.

--
Sohail Somani
http://uint32t.blogspot.com
 
Reply With Quote
 
SG
Guest
Posts: n/a
 
      05-07-2009
On 7 Mai, 21:34, Sohail Somani <(E-Mail Removed)> wrote:
> SG wrote:
> > I had to look into the draft again to check whether it actually does
> > what you seem to think it does [...]

>
> I had to double-check as well
> Just to clarify, your understanding comes from [expr.prim.lambda]/7 ?


In N2857.pdf it's 5.2.1/8 [expr.prim.lambda] where it says that the
"object type" in case of a reference is the type the reference refers
to.

> [...]
> for(iterator it1, it2, it3 ...)
> {
> * functions.push_back([t1=*it1,t2=*it2,t3=*it3]()
> * * * * * * * * * * * {whatever(t1,t2,t3);});
> }


You could use std::bind here. Nobody forces you to use lambdas.

functions.push_back(std::bind(whatever,*it1,*it2,* it3));


Cheers!
SG
 
Reply With Quote
 
Sohail Somani
Guest
Posts: n/a
 
      05-07-2009
SG wrote:
> On 7 Mai, 21:34, Sohail Somani <(E-Mail Removed)> wrote:
>> SG wrote:
>>> I had to look into the draft again to check whether it actually does
>>> what you seem to think it does [...]

>> I had to double-check as well
>> Just to clarify, your understanding comes from [expr.prim.lambda]/7 ?

>
> In N2857.pdf it's 5.2.1/8 [expr.prim.lambda] where it says that the
> "object type" in case of a reference is the type the reference refers
> to.
>
>> [...]
>> for(iterator it1, it2, it3 ...)
>> {
>> functions.push_back([t1=*it1,t2=*it2,t3=*it3]()
>> {whatever(t1,t2,t3);});
>> }

>
> You could use std::bind here. Nobody forces you to use lambdas.
>
> functions.push_back(std::bind(whatever,*it1,*it2,* it3));


I thought you had to use lambda?!!! Just kidding

Of course, you are right. However, once you have more than one function
call involved, you can't use bind:

functions.push_back([<something to keep *itN>](){
whatever(*it1,*it2,*it3);
something_else(*it1,*it2,*it3);
});

Here is another example:

bind(&Session::connect,config.server(),config.user name(),config.password());

The equivalent in C++0x lambda is too noisy to use. I cannot hold config
by reference because of (unlikely but possible) thread-safety issues.

Anyway, I just wanted to be sure that bind is still useful and you
shouldn't feel bad for using it

--
Sohail Somani
http://uint32t.blogspot.com
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Lambda function capturing and memory usage Juha Nieminen C++ 6 04-24-2012 04:26 PM
Lambda function capturing and memory usage Juha Nieminen C++ 1 04-22-2012 12:22 PM
Computed values don't tie up James Kuyper C Programming 13 04-04-2012 03:42 AM
How do I put computed values in 'formview' COHENMARVIN@lycos.com ASP .Net 2 05-05-2008 11:20 PM
Re: Lambda as declarative idiom (was RE: what is lambda used for inreal code?) Roman Suzi Python 13 01-07-2005 09:33 PM



Advertisments