Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

lambda capture using references in scope

478 views
Skip to first unread message

gas...@hotmail.com

unread,
Jul 25, 2012, 1:03:26 PM7/25/12
to
Hello all,

i was surprised the other day that when u pass references in lambda's they actually get copied when capturing by value. If u pass a pointer, the pointer gets copied, but not the pointee. However if u pass a reference also the thing the reference points to
get copied. Its the reverse what I would expect (atm) but oth the c++ committee often does that :(. But maybe someone has a powerful explanation?

Example:

void Foo()
{
std::string str;
std::string& rstr = str;
std::vector<int> vec(1);

printf("%08x", &rstr);

//a copy of rstr will be made???
std::for_each(vec.cbegin(), vec.cend(), [=] (int n)
{
//rstr gets copied
printf("%08x", &rstr);
});

std::for_each(vec.cbegin(), vec.cend(), [&] (int n)
{
printf("%08x", &rstr);
});
}

Using vs2010.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

jack....@perkinelmer.com

unread,
Aug 1, 2012, 2:48:36 PM8/1/12
to
On Wednesday, July 25, 2012 1:03:26 PM UTC-4, gas...@hotmail.com wrote:
> Hello all,
>
> i was surprised the other day that when u pass references in
> lambda's they actually get copied when capturing by value. If u pass
> a pointer, the pointer gets copied, but not the pointee. However if
> u pass a reference also the thing the reference points to
>
> std::for_each(vec.cbegin(), vec.cend(), [=] (int n)

Looks like your lambda captures by value. Change to capture
by ref. Change the [=] to [&] and the copy should go away.

TheGunslinger

unread,
Aug 2, 2012, 12:27:43 AM8/2/12
to
Here is a code snippet from Sams Learn C++ in One Hour a Day, 7th
Edition, which covers Lambda functions (and the C++11 standard
updates) and expressions, page 161, Listing 7.11:

void DisplayNums(vector<int>& DynArray)
{
for_each (DynArray.begin(), DynArray.end(), \
[] (int Element) {cout << Element << " ";} ); // Lambda

cout << endl;
}

Since vectors are a template class, you should be able to substitute
<str> or <char> for <int>

Hope this helps.

Respectfully,

MJR

gas...@hotmail.com

unread,
Aug 2, 2012, 4:11:29 PM8/2/12
to
> Looks like your lambda captures by value. Change to capture
>
> by ref. Change the [=] to [&] and the copy should go away.

Yes but that's not the point I made. See my original post.

John G Harris

unread,
Aug 2, 2012, 4:12:40 PM8/2/12
to
On Wed, 1 Aug 2012 at 21:27:43, in comp.lang.c++.moderated,
TheGunslinger wrote:
> On Wed, 25 Jul 2012 10:03:26 -0700 (PDT), "gas...@hotmail.com"
> <gas...@hotmail.com> wrote:

<snip>
> Here is a code snippet from Sams Learn C++ in One Hour a Day, 7th
> Edition, which covers Lambda functions (and the C++11 standard
> updates) and expressions, page 161, Listing 7.11:
>
> void DisplayNums(vector<int>& DynArray)
> {
> for_each (DynArray.begin(), DynArray.end(), \

Is the backslash at the end of the line really necessary? If so, what
happens if it's inadvertently followed by some spaces?


> [] (int Element) {cout << Element << " ";} ); // Lambda
>
> cout << endl;
> }
<snip>

John
--
John Harris

hans...@hotmail.com

unread,
Aug 9, 2012, 2:50:26 PM8/9/12
to
{ Reformatted; please limit your lines to 70 characters -mod }

Since your first lambda (anonymous function) specifies 'capture
(i.e. pass) by value' the lambda function behaviour is consitent with
normal parameter passing in C++.

Hans

gas...@hotmail.com

unread,
Aug 10, 2012, 2:18:52 PM8/10/12
to
> Since your first lambda (anonymous function) specifies 'capture
>
> (i.e. pass) by value' the lambda function behaviour is consitent with
>
> normal parameter passing in C++.
>
>
> Hans

Is it, e.g. void f(const std::string& rstr) it passes the reference and doesn't copy.

hans...@hotmail.com

unread,
Aug 13, 2012, 3:42:20 PM8/13/12
to
{ Your article lacks the context of what it's referring to.
Please include some quoting to establish the context. -mod }

{ Please limit your text to fit within 80 columns, preferably around 70,
so that readers don't have to scroll horizontally to read each line.
This article has been reformatted manually by the moderator. -mod }

Hi, not exactly sure I understand what you mean.

Your first lambda captures by value (i.e. [=]). So if you grab an entity
inside the lambda which is declared as a reference in the enclosing
environment you will get a copy of it since you implicitly have stated
that the environment should be passed by value into the lambda. This is
consistent with normal parameter passing.

I know that you asked for a reason for the behaviour (which I hope I
gave),not a ref to the standard, but here is the standard anyway:

------ 5.1.2 ------
14 An entity is captured by copy if it is implicitly captured and the
capture default is = or if it is explicitly captured with a capture that
does not include an &. For each entity captured by copy, an unnamed
nonstatic data member is declared in the closure type. Blah, blah ...

15 An entity is captured by reference if it is implicitly or explicitly
captured but not captured by copy. Blah, blah ...
------

In your case for your first lambda, point 14 is applicable.

Regards,
Hans

Daniel Krügler

unread,
Aug 30, 2012, 4:40:38 PM8/30/12
to

[4th attempt after several weeks]

Am 25.07.2012 19:03, schrieb gas...@hotmail.com:
> i was surprised the other day that when u pass references in
> lambda's they actually get copied when capturing by value. If u
> pass a pointer, the pointer gets copied, but not the pointee.
> However if u pass a reference also the thing the reference points
> to get copied. Its the reverse what I would expect (atm) but oth
> the c++ committee often does that. But maybe someone has a powerful
> explanation?

Actually I find the specified behaviour very intuitive: If you capture
by value, this behaves as like copy-initialization of a "by-value"
variable, if you capture by reference, this behaves like a
by-reference parameter of the referenced type. If we decide for either
of these parameter types, this decision does not depend on whether the
argument is a reference or not. In fact, references that enter
expressions *always* behave as if the reference had been removed
first, see [expr] p5:

"If an expression initially has the type “reference to T” (8.3.2,
8.5.3), the type is adjusted to T prior to any further analysis."

In regard to pointers, these are just objects that can be copied, so
they are copied via a = capture as well.

Both behaviours are so important as part of C++ that any different
deduction form would be controversial (I just add as a remark that
capture of "this" is one of the more irritating things).

A similar *analogy* applies to function template deduction by
argument: The = capture corresponds to deducing a parameter type from
this signature form:

template<class T>
void f(T);

This will always determine T to a non-reference type, irrespective of
the value category of the argument or whether the argument is a
reference type or not.

The & capture corresponds to deducing a parameter type from this
signature form:

template<class T>
void f(&T);

and will always bind directly to the referenced argument. Again, this
deduction does not depend on whether the argument is a referenced type
or not.

HTH & Greetings from Bremen,

Daniel Krügler
0 new messages