#include <iostream>
#include <string>
#include <vector>
class X
{
public:
int& a;
int&& b;
X(int& c, int && d):a(c), b(std::move(d))
{
}
};
X* x = nullptr;
void fun()
{
std::cout<<"Fun\n";
int l = 8;
int r = 9;
std::cout << &(l) << std::endl;
std::cout << &(r) << std::endl;
x = new X(l, std::move(r));
}
int main()
{
fun();
std::cout << x->a << std::endl;
std::cout << &(x->a) << std::endl;
std::cout << x->b << std::endl;
std::cout << &(x->b) << std::endl;
}
=> Will values of member variable references (lvalue and rvalue) be garbage?
I am seeing different behavior across different compilers. So wanted to know what c++ standard says about this.
You're binding reference members to local variables, which will be destroyed when get out of the function fun(). After that, both references become dangled, any dereference on them leads to UB.
This is true for both lvalue and rvalue reference members.
Related
In the following code an object is overwritten with a new object of same type, where a lambda-expression creates a closure that uses this of the old object. The old address (this) remains the same, the new object has the same layout, so this should be ok and not UB. But what about non trivial objects or other cases?
struct A {
void g(A& o, int v) {
o = A{.x = v, .f = [this]{
std::cout << "f" << this->x << '\n';
}};
}
int x{0};
std::function<void()> f;
~A() {
std::cout << "dtor" << x << '\n';
}
};
void test() {
A a;
a.g(a, 2);
a.f();
}
You are not actually replacing any object. You are just assigning from another object to the current one. o = simply calls the implicit copy assignment operator which will copy-assign the individual members from the temporary A constructed in the assignment expression with A{...}.
The lambda is going to capture this from this in g, not from the temporary object.
std::function will always keep a copy of the lambda referring to the original object on which g was called and since that is its parent object, it cannot outlive it.
So there is no problem here. The only exception would be that you call f during the destruction of the A object, in which case using the captured pointer may be forbidden.
Here is a slightly modified code with a corner case. I create a temporary in a function and call g on it passing it a more permanent object. The temporary vanishes and the long life object now has a closure refering to an object after its end of life. Invoking f is UB:
#include <iostream>
#include <functional>
struct A {
void g(A& o, int v) {
o = A{ .x = v, .f = [this] {
std::cout << "f" << this->x << ' ' << this << '\n';
} };
}
int x{ 0 };
std::function<void()> f;
~A() {
std::cout << "dtor" << x << ' ' << this << '\n';
}
};
void test(A& a) {
A b{ 2 };
b.g(a, 3);
}
int main() {
A a{ 1 };
std::cout << a.x << '\n';
test(a);
std::cout << a.x << '\n';
a.f(); // UB because a.f uses an object after its end of life
}
The output is:
1
dtor3 0135F9C0
dtor2 0135FA30
3
f341072 0135FA30
dtor3 0135FAA8
proving that the invocation of a.f() tried to use the object at address 0135FA30 (in that specific run) after it has been destroyed.
I have this example code:
// Copyright 2019 Google LLC.
// SPDX-License-Identifier: Apache-2.0
#include <functional>
#include <iostream>
#include <string>
void f(std::function<const std::string&()> fn) {
std::cout << "in f" << std::endl;
std::cout << "str: " << fn() << std::endl;
}
int main() {
std::string str = "a";
auto fn1 = [&]() { return str; };
auto fn2 = [&]() { const std::string& str2 = str; return str2; };
auto fn3 = [&]() -> const std::string& { return str; };
std::cout << "in main" << std::endl;
std::cout << "fn1: " << fn1() << std::endl;
std::cout << "fn2: " << fn2() << std::endl;
std::cout << "fn3: " << fn3() << std::endl;
f(fn1); // Segfaults
f(fn2); // Also segfaults
f(fn3); // Actually works
return 0;
}
When I first wrote this I expected that calling fn1() inside f() would properly return a reference to the str in main. Given that str is allocated until after f() returns, this looked fine to me. But what actually happens is that trying to access the return of fn1() inside f() segfaults.
The same thing happens with fn2(), but what is surprising is that fn3() works properly.
Given that fn3() works and fn1() doesn't, is there something I'm missing about how C++ deduces the return values of lambda functions? How would that create this segfault?
For the record, here are the outputs if I run this code:
calling only f(fn3):
in main
fn1: a
fn2: a
fn3: a
in f
str: a
calling only f(fn2):
in main
fn1: a
fn2: a
fn3: a
in f
Segmentation fault (core dumped)
calling only f(fn1):
in main
fn1: a
fn2: a
fn3: a
in f
Segmentation fault (core dumped)
A lambda without trailing return type as in:
[&](){return str;};
Is equivalent to:
[&]()->auto{return str;};
So this lambda returns a copy of str.
Calling the std::function object will result in this equivalent code:
const string& std_function_call_operator(){
// functor = [&]->auto{return str;};
return functor();
}
When this function is called, str is copied inside a temporary, the reference is bound to this temporary and then the temporary is destroyed. So you get the famous dangling reference. This is a very classical scenario.
The return type deduction of lambda is changed N3638. and now the return type of a lambda uses the auto return type deduction rules, which strips the referenceness.
Hence, [&]() { return str;}; returns string. As a result, in void f(std::function<const std::string&()> fn) calling fn() returns a dangling reference. Binding a reference to a temporary extends the lifetime of the temporary, but in this case the binding happened deep inside std::function's machinery, so by the time f() returns, the temporary is gone already.
lambda deduction rule
auto and lambda return types use slightly different rules for
determining the result type from an expression. auto uses the rules in
17.9.2.1 [temp.deduct.call], which explicitly drops top-level cv-qualification in all cases, while the lambda return type is based
on the lvalue-to-rvalue conversion, which drops cv-qualification only
for non-class types. As a result:
struct A { };
const A f();
auto a = f(); // decltype(a) is A
auto b = []{ return f(); }; // decltype(b()) is const A This seems like an unnecessary inconsistency.
John Spicer:
The difference is intentional; auto is intended only to give a const
type if you explicitly ask for it, while the lambda return type should
generally be the type of the expression.
Daniel Krügler:
Another inconsistency: with auto, use of a braced-init-list can deduce
a specialization of std::initializer_list; it would be helpful if the
same could be done for a lambda return type.
Additional note, February, 2014:
EWG noted that g++ and clang differ in their treatment of this example
and referred it back to CWG for resolution.
Let's see what is deduced in your code:
fn1: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
fn2: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
fn3: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&
as you can see only the last one is actually a const&
you can check return types of your lambdas with the following code:
//https://stackoverflow.com/a/20170989/10933809
#include <functional>
#include <iostream>
#include <string>
void f(std::function<const std::string&()> fn) {
std::cout << "in f" << std::endl;
std::cout << "str: " << fn() << std::endl;
}
#include <type_traits>
#include <typeinfo>
#ifndef _MSC_VER
# include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>
template <class T>
std::string
type_name()
{
typedef typename std::remove_reference<T>::type TR;
std::unique_ptr<char, void(*)(void*)> own
(
#ifndef _MSC_VER
abi::__cxa_demangle(typeid(TR).name(), nullptr,
nullptr, nullptr),
#else
nullptr,
#endif
std::free
);
std::string r = own != nullptr ? own.get() : typeid(TR).name();
if (std::is_const<TR>::value)
r += " const";
if (std::is_volatile<TR>::value)
r += " volatile";
if (std::is_lvalue_reference<T>::value)
r += "&";
else if (std::is_rvalue_reference<T>::value)
r += "&&";
return r;
}
int main() {
std::string str = "a";
auto fn1 = [&]() { return str; };
auto fn2 = [&]() { const std::string& str2 = str; return str2; };
auto fn3 = [&]() -> const std::string& { return str; };
std::cout << "in main" << std::endl;
std::cout << "fn1: " << fn1() << std::endl;
std::cout << "fn2: " << fn2() << std::endl;
std::cout << "fn3: " << fn3() << std::endl;
auto f1=fn1();
std::cout << "fn1: " << type_name<decltype(fn1())>() << std::endl;
std::cout << "fn2: " << type_name<decltype(fn2())>() << std::endl;
std::cout << "fn3: " << type_name<decltype(fn3())>() << std::endl;
f(fn1); // Segfaults
f(fn2); // Also segfaults
f(fn3); // Actually works
return 0;
}
Sample:
#include "stdafx.h"
#include <functional>
#include <iostream>
#include <string>
std::function<void(int)> Foo()
{
int v = 1;
int r = 2;
auto l = [v, r](int i)
{
std::cout << v << " " << r << " " << i << std::endl;
};
return l;
}
int main()
{
auto func = Foo();
func(3);
return 0;
}
Why func(3) can pass 3 to i which is the formal argument of the lambda in Foo(). I can't think out. thanks.
TL;DR: You don't pass your argument 3 into a function Foo. You pass it to a method of an object func.
A bit more detailed explanation is below.
First of all, I would like to clarify what a lambda is. A lambda in C++ is nothing more than an anonymous functor class, so essentially just a syntactic sugar. A closure is an instance of a lambda type. However, quite often you can hear words "lambda" and "closure" being used interchangeably.
So within your function Foo() you create a closure object l
auto l = [v, r](int i)
{
std::cout << v << " " << r << " " << i << std::endl;
};
which would be technically equivalent to this code:
struct Functor
{
Functor(int v, int r) : v_(v), r_(r) {}
void operator ()(int i) const {
std::cout << v_ << " " << r_ << " " << i << std::endl;
}
private:
int v_;
int r_;
};
Functor l(v, r);
Now, on the next line you return an std::function object.
return l; // actually creates std::function<void(int)>(l) and returns it
So in your main function a func is just an object which stores copies of values v, r obtained during a call to Foo() and defines operator(), similar to the struct above.
Therefore, calling func(3) you actually invoke an object method on a concrete object func, and without syntactic sugar it looks like func.operator()(3).
Here's a live example to illustrate my point.
Hope that helps to resolve your confusion.
Given example:
#include <iostream>
#include <cstdlib>
#define PRINT_NAME { std::cout << __PRETTY_FUNCTION__ << std::endl; }
namespace
{
struct A
{
A() { PRINT_NAME; }
~A() { PRINT_NAME; }
};
A f() { return {}; }
A b;
A && g() { return std::move(b); }
}
int
main()
{
std::cout << "------------------" << std::endl;
{
f();
std::cout << 1 << std::endl;
}
std::cout << "------------------" << std::endl;
{
A && a = f();
// or A const & a = f(); as mentioned in below discussion
std::cout << 2 << std::endl;
}
std::cout << "------------------" << std::endl;
{
A && a = g();
std::cout << 3 << std::endl;
}
std::cout << "------------------" << std::endl;
return EXIT_SUCCESS;
}
and its output (of clang 3.5.0):
(anonymous namespace)::A::A()
------------------
(anonymous namespace)::A::A()
(anonymous namespace)::A::~A()
1
------------------
(anonymous namespace)::A::A()
2
(anonymous namespace)::A::~A()
------------------
3
------------------
(anonymous namespace)::A::~A()
What is the semantic rule: an thinkable shortand of the standard's paragraphs, which compactly summarizes the difference in destructors behaviour regarding above code sample? I often faces "idiomatic rules" formulated via the "have some (non-obviously relevant) characteristic" or "have some inherent attribute" statements, e.g. "if it has a name, then it is an lvalue". Is there something similar?
This has nothing to do with rvalue references. In fact, if you change A&& to const A& throughout the code, the behavior won't change.
Probably your confusion is caused by the name of std::move() function. It doesn't actually move anything, it just casts its argument to rvalue reference.
Don't think about destructors, think about lifetime of objects. Personally I don't know a simple rule of thumb (apart from "read the standard"), but these three rules may help you:
Static objects have (basically) lifetime of the whole program.
If a temporary object returned from a function is not bound to anything, it's lifetime ends when the whole expression execution finishes.
If a temporary object returned from a function is bound to some reference, its lifetime is extended to a lifetime of that reference.
This is a spin off of the question How to check if object is const or not?.
I was surprised to see the following program
#include <iostream>
#include <type_traits>
int main()
{
std::cout << std::boolalpha;
std::cout << std::is_const<const int&>::value << "\n";
}
produced this output
false
In what context does it make sense to think of const int& as a non-const type?
Perhaps it'll be easier to understand with this example
std::cout << std::is_const<int const *>::value << "\n"; // pointer to const int
std::cout << std::is_const<int * const>::value << "\n"; // const pointer to int
Output:
false
true
The first type is a pointer to a const int, while in the second the int * itself is const. Hence it results in true while the former is false. Similarly, what you have a reference to a const int. If int& const were valid it'd result in true.
A const qualifier on a reference just means that the value can't be modified via the reference. It can still be modified by other means. For example:
int a = 1;
const int &b = a;
std::cout << b << std::endl; // Prints 1
a = 2;
std::cout << b << std::endl; // Prints 2
Thus, you can't assume that the value of a const reference is actually constant.