Reading the answer from Capturing a reference by reference in a C++11 lambda makes me think that the following code generates undefined behavior because of the ended lifetime of i in the lambda-capture. Is that right for C++1y? I am asking because g++ 4.8.2 translates the code just fine.
#include <iostream>
auto captureFct( ) {
int i=0;
auto set = [&i](int _i){ i=_i; };
auto get = [&i](){ return i; };
return std::pair<decltype(set),decltype(get)>(set,get);
}
int main() {
auto myPair = captureFct();
auto set1 = myPair.first;
auto get1 = myPair.second;
auto myPair1 = captureFct();
auto set2 = myPair1.first;
auto get2 = myPair1.second;
std::cout << "\nget1:" << get1() << " get2:" << get2() << '\n';
set1(1); set2(2);
std::cout << "\nget1:" << get1() << " get2:" << get2();
}
/*
Local Variables:
compile-command: "g++ -std=c++1y lambda.cc -o a.exe && ./a.exe"
End:
*/
The output is interesting:
get1:0 get2:0
get1:2 get2:2
It seems that the same reference is used for all lambdas.
This behavior differs from the behavior of the following elisp code (as close to the c++ code as possible):
(defun captureFct ()
(lexical-let ((i 0))
(list :set (lambda (_i) (setq i _i))
:get (lambda () i))))
(setq myPair (captureFct))
(setq myPair1 (captureFct))
(message "\nget1: %d get2: %d"
(funcall (plist-get myPair :get))
(funcall (plist-get myPair1 :get)))
(funcall (plist-get myPair :set) 1)
(funcall (plist-get myPair1 :set) 2)
(message "\nget1: %d get2: %d"
(funcall (plist-get myPair :get))
(funcall (plist-get myPair1 :get)))
The output of the elisp code is:
get1: 0 get2: 0
get1: 1 get2: 2
I think I know already the answer. But, I post this question anyway since it is interesting for folks that do both elisp and c++.
Last but not least a C++ version that works like the elisp version:
#include <iostream>
#include <memory>
auto captureFct( ) {
std::shared_ptr<int> pi(new int(0));
auto set = [pi](int _i){ *pi=_i; };
auto get = [pi](){ return *pi; };
return std::pair<decltype(set),decltype(get)>(set,get);
}
int main() {
auto myPair = captureFct();
auto set1 = myPair.first;
auto get1 = myPair.second;
auto myPair1 = captureFct();
auto set2 = myPair1.first;
auto get2 = myPair1.second;
std::cout << "\nget1:" << get1() << " get2:" << get2() << '\n';
set1(1); set2(2);
std::cout << "\nget1:" << get1() << " get2:" << get2();
}
/*
Local Variables:
compile-command: "g++ -std=c++1y lambda.cc -o a.exe && ./a.exe"
End:
*/
Yes, it's undefined behaviour, since the references inside the lambdas become dangling as soon as captureFunc() exits (*).
What's probably happening in your case is that the references (which are just pointers under the hood) still point to the space on the stack where i was on the first invocation of captureFunc(), and it ends up in exactly the same location on the second invocation of captureFunc(); so the net effect is that all of get1, get2, set1, set2 have their internal i reference pointed to the same (currently unused) location in memory, so they modify it for each other.
Of course, the above is just speculation, and could change next time you (or run) the program, since Undefined Behaviour is Undefined.
(*) Quoting C++11, [expr.prim.lambda]§22:
[ Note: If an entity is implicitly or explicitly captured by reference, invoking the function call operator of
the corresponding lambda-expression after the lifetime of the entity has ended is likely to result in undefined
behavior. —end note ]
Related
Here is a code snippet I have :
struct PairHasher {
size_t operator()(const std::pair<std::string_view, std::string_view>& stop_stop) const {
return hasher(stop_stop.first) + 37*hasher(stop_stop.second);
}
std::hash<std::string_view> hasher;
};
BOOST_FIXTURE_TEST_CASE(unordered_map_string_view_pair_must_be_ok, TestCaseStartStopMessager)
{
const std::vector<std::string> from_stops = {"from_0", "from_1", "from_2"};
const std::vector<std::string> to_stops = {"to_0", "to_1", "to_2"};
std::unordered_map<std::pair<std::string_view, std::string_view>, std::int32_t, TransportCatalogue::PairHasher> distance_between_stops;
for ( std::size_t idx = 0; idx < from_stops.size(); ++idx) {
std::cout << from_stops[idx] << " : " << to_stops[idx] << std::endl;
distance_between_stops[std::pair(from_stops[idx], to_stops[idx])] = idx;
}
std::cout << "MAP CONTENT :" << std::endl;
for (auto const& x : distance_between_stops)
{
std::cout << x.first.first << " : " << x.first.second << std::endl;
}
}
I expect to see 3 pairs inside the container, but there is only 1 concerning to the output :
MAP CONTENT :
from_2 : to_2
So, where are two more pair lost? What am I doing wrong?
Moving my comment to an answer.
This is pretty sneaky. I noticed in Compiler Explorer that changing:
distance_between_stops[std::pair(from_stops[idx], to_stops[idx])] = idx;
to
distance_between_stops[std::pair(std::string_view{from_stops[idx]}, std::string_view{to_stops[idx]})] = idx;
fixes the bug. This hints that the problem lies in some implicit string -> string_view conversion. And indeed that is the case, but it is hidden behind one extra layer.
std::pair(from_stops[idx], to_stops[idx]) creates a std::pair<std::string, std::string>, but distance_between_stops requires a std::pair<std::string_view, std::string_view>. When we insert values into the map, this conversion happens implicitly via overload #5 here:
template <class U1, class U2>
constexpr pair(pair<U1, U2>&& p);
Initializes first with std::forward<U1>(p.first) and second with std::forward<U2>(p.second).
This constructor participates in overload resolution if and only if std::is_constructible_v<first_type, U1&&> and std::is_constructible_v<second_type, U2&&> are both true.
This constructor is explicit if and only if std::is_convertible_v<U1&&, first_type> is false or std::is_convertible_v<U2&&, second_type> is false.
(For reference, std::is_constructible_v<std::string_view, std::string&&> and std::is_convertible_v<std::string&&, std::string_view> are both true, so we know this overload is viable and implicit.)
See the problem yet? When we use the map's operator[], it has to do an implicit conversion to create a key with the proper type. This implicit conversion constructs a pair of string_views that are viewing the temporary memory from the local pair of strings, not the underlying strings in the vector. In other words, it is conceptually similar to:
std::string_view foo(const std::string& s) {
std::string temp = s + " foo";
return temp;
}
int main() {
std::string_view sv = foo("hello");
std::cout << sv << "\n";
}
Clang emits a warning for this small example, but not OP's full example, which is unfortunate:
warning: address of stack memory associated with local variable 'temp' returned [-Wreturn-stack-address]
return temp;
^~~~
Imagine you have the following code where logDebug() is expensive or is not appropriate to call more than once:
QDebug d = logDebug();
d << __FUNCTION__ << ":";
d << "positions separated with \" --- \":";
for (const auto& str : positions)
{
d << "---" << str;
}
A macro (just to replace the function name correctly) already exists which replaces the first 2 lines:
#define LOG_FUNCTION this->logDebug() << __FUNCTION__ << ":"
It creates the local variable by calling logDebug(). Once called, you can only use the operator<< onto the macro.
The problem is you can't attach the for loop body to logger.
Q: Is there a way I could use the macro for pasting all the positions (without calling logDebug again?
I would guess this should be possible using lambdas, but I quite don't know how to.
Please help, the shortest answer wins!
Q: Is there a way I could use the macro for pasting all the positions (without calling logDebug again? I would guess this should be possible using lambdas, but I quite don't know how to.
I suppose it's possible with something as follows (used std::cout instead of logDebug())
#include <iostream>
#define LOG_FUNCTION std::cout << __FUNCTION__ << ": "
#define LOG_DEB(ps) \
[](auto & s, auto const & _ps) { for ( auto const & p : _ps ) s << p; } \
(LOG_FUNCTION, ps)
int main ()
{
int a[] { 0, 1, 2, 3, 4 };
LOG_DEB(a);
}
I've used a couple of auto as types of the lambda arguments and this works only starting from C++14.
In C++11 you have to replace they with the correct types.
Well the macro can be coerced to return your debug object:
#define LOG_FUNCTION() this->logDebug() << __FUNCTION__ << ":"
Then use it like this:
auto& d = LOG_FUNCTION();
d << "positions separated with \" --- \":";
for (const auto& str : positions)
{
d << "---" << str;
}
int main(){
auto func1 = [](int y) {
cout << y << " ";
};
auto func2 = [](int y) {
cout << y * y << " ";
};
cout << "func1 is : " << typeid(func1).name() << endl;
cout << "func2 is : " << typeid(func2).name() << endl;
cout << "main is : " << typeid(main).name() << endl;
}
OSX output:
func1 is : Z4mainE3$_0
func2 is : Z4mainE3$_1
main is : FivE
Can someone explain the output ??
Thanks, I am just exploring some c++11 features.
What you are seeing here is the name mangled name of each of these symbols. This is what typeid.name() for your compiler implementation returns. There is no requirement that the mangled name precisely relates directly to your code. Using the mangled symbol names already present in the object files for linking is a convenient implementation choice.
You can unmangle names using the c++filt tool:
Thus:
$ c++filt _FivE
yields
int ()
In other words, a function returning an int. Remember that what you are asking for here is the type of the function and not its name.
If you were to apply this to a class
class foo
{
};
cout << "foo is : " << typeid(foo).name() << endl;
You will find output is 3foo and the unmanged name foo.
The two lambdas don't unmangle. This is because they are anonymous functions, so don't need an external name.
Furthermore, compiler generates a functor class for each lambda. The first of which would look like
struct Z4mainE3
{
void operator()(int y)
{
cout << y << " ";
}
}
This means that each one is a distinct type. The name is synthetic, and generated by the compiler such that is won't collide with anything else.
The typeid operator will operate on the functor struct and not the apparent return and argument type of the lambda itself, hence the two of them are a different type despite apparently being functions having the same signature.
The long-standing advice about typeid().name() operator is that it is not portable; you should not rely on the values returned.
I think I might have missed the subtlety in move construction because when I change the line Foo copy(*this); to decltype(*this) copy(*this);, I am thoroughly surprised by the output.
I checked it against, clang++-3.5 and g++-4.9, with the same behavior.
Would really appreciate a quick tip from the C++11 guru.
Update: Just forced the compiler to print the type of decltype(*this), it is actually a reference type i.e. Foo&.
class Foo {
public:
Foo(int a): val(a) {}
operator int() { return val; }
auto& operator++() {
val++;
return *this;
}
auto operator++(int) {
//Foo copy(*this);
decltype(*this) copy(*this);
++(*this);
return copy;
}
private:
int val;
};
int main()
{
Foo foo=1;
cout << "foo++ = " << foo++ << "\n";
cout << "foo++ = " << foo++ << "\n";
cout << "foo = " << foo << "\n";
return 0;
}
The output
foo++ = 2
foo++ = 3
foo = 3
There seems to be a confusion as to why decltyp(*this) is Foo& and not Foo in your case. Firstly, think about dereferencing a pointer always resulting in a reference to the pointed to object.
temp = *ptr // this would work if dereferencing returned by value or by reference
*ptr = expr // this would only work if dereferencing results in a reference.
Now decltype(expr) always gives you exactly the same type as the expr. For you *this is of type Foo&.
If you want type deduction without it resulting in a reference use auto instead of decltype, so:
auto copy(*this);
instead of
decltype(*this) copy(*this);
Also I don't know why your question is talking about move construction so much as there is no move involved anywhere.
class MyClass{
public:
MyClass() {}
virtual ~MyClass() {}
};
extern "C" int foo(int tryNumber)
{
std::tr1::shared_ptr<MyClass> myClass(new MyClass());
std::cout << "Object has been created " << tryNumber << << std::endl;
return 0;
}
Then somewhere in my program I write:
for (int i = 0; i < 10000; ++i){
foo(i);
}
There are the facts:
1) gcc 4.0.1, and I can't update them yet. So when I implement std::tr1::shared_ptr, I see the complier uses boost/shared_ptr.hpp (boost 1.33.1)
2) Well, the program uses many threads, I even don't know how they do work and what they do completely (the large project at my job), but I know, that I don't use any shared variables or something else that can cause this behavior
3) Sometimes it just prints:
Object has been created 0
Object has been created 1
...
Object has been created 9999
And everything is ok
Sometimes it prints 0-1-2-3-4 (or more) lines and then stops. Furthermore - I know, that the object has been created, but function hasn't returned the value and program just freezes, and when I try to attach to the program with gdb and type "where" - I see this:
0) 0xb7fd8430 in __kernel_vsyscall ()
1) 0xb7d9bece in _lll_mutex_lock-wait() from /lib/i686/libpthread.so.0
2) 0xb7d98500 in _L_mutex_lock_71 () from /lib/i686/libpthread.so.0
3) 0xbfbefab8 in ?? ()
4) 0x00000000 in ?? ()
Or this:
0) 0xb7fd8430 in __kernel_vsyscall ()
1) 0xb7d9bece in _lll_mutex_lock-wait() from /lib/i686/libpthread.so.0
2) 0xb7d98500 in _L_mutex_lock_71 () from /lib/i686/libpthread.so.0
..dunno what is here, I see only " .. in ?? ()"
10) .. in __gthread_mutex_lock
11) .. in __gthread_mutex_lock
12) .. in std::tr1::_Sp_counted_base::release
13) .. in ~shared_count
14) .. in ~shared_ptr
Seems it like shared_ptr is broken?
I just solved this issue. Changed this:
#include <tr1/memory> to #include <boost/shared_ptr.hpp>
std::tr1::shared_ptr to boost::shared_ptr
The solution is described here link