Spurious warning about binding temporary to reference member in constructor - c++

I understand that if a temporary is bound to a reference member in the constructor's initializer list, the object will be destroyed as the constructor returns.
However, consider the following code:
#include <functional>
#include <iostream>
using callback_func = std::function<int(void)>;
int
func(const callback_func& callback)
{
struct wrapper
{
const callback_func& w_cb;
wrapper(const callback_func& cb) : w_cb {cb} { }
int call() { return this->w_cb() + this->w_cb(); }
};
wrapper wrp {callback};
return wrp.call();
}
int
main()
{
std::cout << func([](){ return 21; }) << std::endl;
return 0;
}
This looks perfectly valid to me. The callback object will live during the whole execution of the func function and no temporary copy should be made for wrapper's constructor.
Indeed, GCC 4.9.0 compiles fine with all warnings enabled.
However, GCC 4.8.2 compiler gives me the following warning:
$ g++ -std=c++11 -W main.cpp
main.cpp: In constructor ‘func(const callback_func&)::wrapper::wrapper(const callback_func&)’:
main.cpp:12:48: warning: a temporary bound to ‘func(const callback_func&)::wrapper::w_cb’ only persists until the constructor exits [-Wextra]
wrapper(const callback_func& cb) : w_cb {cb} { }
^
Is this a false positive or am I misunderstanding the object lifetimes?
Here are my exact compiler versions tested:
$ g++ --version
g++ (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ --version
g++ (GCC) 4.9.0 20140604 (prerelease)
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

This is a bug in gcc 4.8 that has been fixed in 4.9. Here is the bug report:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50025

As pointed out by Howard Hinnant and already indicated by R Sahu's comment, this is a bug (which used to be required by the then-broken standard; thanks to Tony D for pointing this out) in the way GCC 4.8 is treating initializer lists.
Changing the constructor in my original example from
wrapper(const callback_func& cb) : w_cb {cb} { }
to
wrapper(const callback_func& cb) : w_cb (cb) { }
makes the warning with GCC 4.8.3 go away and the created executable Valgrind clean. The diff of the two assembly files is huge so I don't post it here. GCC 4.9.0 creates identical assembly code for both versions.
Next, I replaced the std::function with a user-defined struct and deleted copy and move constructors and assignment operators. Indeed, with GCC 4.8.3, this retains the warning but now also gives a (slightly more helpful) error that the above line of code calls the deleted copy constructor of the struct. As expected, there is no difference with GCC 4.9.0.

Related

Why [[likely]] attribute in C++20 raises a warning here?

#include <iostream>
int foo(int a, int b)
{
if(a < b) [[likely]] {
return a;
}
return b;
}
int main()
{
std::cout << foo(3,1) << std::endl;
}
Demo
According to the reference, it seems like this is how we're supposed to decorate if clauses with [[likely]] or [[unlikely]] attributes. It's also supported in C++20 (see here).
However, I'm running into a warning:
main.cpp: In function 'int foo(int, int)':
main.cpp:5:15: warning: attributes at the beginning of statement are ignored [-Wattributes]
5 | if(a < b) [[likely]] {
| ^~~~~~~~~~
The codebase is strict about warnings, and this will cause builds to fail. So, am I doing something wrong, or is this a bug?
g++ version on my macbook:
g++-9 (Homebrew GCC 9.3.0_1) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
There's nothing wrong with your code. This is due to GCC's implementer overlooking the fact that attributes on compound-statements are a thing.
[[likely]] if (whatever) {} means something else entirely - it means that the if statement itself is "likely", not a branch of it.

thread_local x(2) doesn't call constructor

thread_local is defined in C++11 to have dynamic initialization semantics, so that it is permissible to declare non-POD types as thread local. However, in this program, I get an unexpected result:
#include <iostream>
struct A {
A() : repr_(0) {}
A(int) : repr_(2) {}
int repr_;
};
thread_local A x(2);
int main() {
std::cerr << x.repr_ << "\n";
return 0;
}
On GCC 4.8 I get:
$ g++ --version
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ -std=c++11 test.cpp && ./a.out
0
The program works correctly if I replace the thread_local line with:
thread_local A x = A(2);
What's going on here?

strict aliasing within struct

I have a class that I use to reinterpret data, but the underlying data is of the same type and yet doing this seems to violate strict aliasing. I would like to be able to reinterpret_cast to choose how to interpret the data. Here's an example:
#include <iostream>
#include <cstdlib>
template <int M>
struct mul {
int i[10];
void multiply(int idx) {
std::cout << i[idx] * M << std::endl;
}
};
void f(mul<1> &s, mul<2> &t) { int i = s.i[0]; t.i[0]++; if (s.i[0] == i) std::abort(); }
int main() {
mul<1> s;
f(s, reinterpret_cast<mul<2> &>(s));
}
The abort shows that this violates strict aliasing even though the basic type is int*. Is there a reason why this should violate strict aliasing? Is there another solution to this style problem - this is a simplified case, imagine a much more complex set of functions and reinterpretations of data using a reinterpret_cast.
I use these reinterpreted types for passing into templatized functions.
Command:
g++-8 -O3 -g test.cpp -o test
Output:
Abort trap: 6
g++-8 --version:
g++-8 (Homebrew GCC HEAD-252870) 8.0.0 20170916 (experimental)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

memory leak under GCC (but not Clang) when throwing in the middle of a C++14 initializer list for std::list<shared_ptr>

Consider the following program:
#include <stdexcept>
#include <stdio.h>
#include <memory>
#include <list>
class Foo {
public:
Foo(){
if (s_ct==0) {throw std::bad_alloc();}
--s_ct;
fprintf(stderr, "ctor %p\n", this);
}
~Foo(){
fprintf(stderr, "dtor %p\n", this);
}
private:
static int s_ct;
};
int Foo::s_ct = 2;
int main(){
try {
std::list<std::shared_ptr<Foo>> l = {
std::make_shared<Foo>(),
std::make_shared<Foo>(),
std::make_shared<Foo>()
};
} catch (std::bad_alloc&) {
fprintf(stderr, "caught exception.\n");
}
fprintf(stderr, "done.\n");
return 0;
}
Compiled like this:
[little:~] $ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[little:~] $ g++ --std=c++14 -o list_init list_init.cc
[little:~] $
The output is:
[little:~] $ ./list_init
ctor 0x1294c30
ctor 0x1294c50
caught exception.
done.
[little:~] $
Notice that the destructors are not called. Valgrind correctly complains of the leak as well.
This seems to violate one of the key purposes of std::make_shared -- namely, that if another expression in the statement throws, the shared object gets properly destroyed because it is wrapped by a fully constructed shared pointer object.
Clang does what I would like here:
[little:~] $ clang++ --version
clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
[little:~] $ clang++ --std=c++14 -o foo list_init.cc
[little:~] $ ./foo
ctor 0x1dfec30
ctor 0x1dfec50
dtor 0x1dfec50
dtor 0x1dfec30
caught exception.
done.
[little:~] $
So is this a GCC bug, or do I need to fix my program?
Turning my comment into an answer so you can mark the question as answered.
This looks to be a gcc bug
Bug 66139 - destructor not called for members of partially constructed anonymous struct/array
Note in particular the last two test cases which use std::initializer_list to illustrate the problem.

error: ‘unique_ptr’ is not a member of ‘std’

I guess it's pretty self explanatory - I can't seem to use C++11 features, even though I think I have everything set up properly - which likely means that I don't.
Here's my code:
#include <cstdlib>
#include <iostream>
class Object {
private:
int value;
public:
Object(int val) {
value = val;
}
int get_val() {
return value;
}
void set_val(int val) {
value = val;
}
};
int main() {
Object *obj = new Object(3);
std::unique_ptr<Object> smart_obj(new Object(5));
std::cout << obj->get_val() << std::endl;
return 0;
}
Here's my version of g++:
ubuntu#ubuntu:~/Desktop$ g++ --version
g++ (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) 4.7.3
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Here's how I'm compiling the code:
ubuntu#ubuntu:~/Desktop$ g++ main.cpp -o run --std=c++11
main.cpp: In function ‘int main()’:
main.cpp:25:2: error: ‘unique_ptr’ is not a member of ‘std’
main.cpp:25:24: error: expected primary-expression before ‘>’ token
main.cpp:25:49: error: ‘smart_obj’ was not declared in this scope
Note that I've tried both -std=c++11 and -std=c++0x to no avail.
I'm running Ubuntu 12.04 LTS from a flash drive on an Intel x64 machine.
You need to include header where unique_ptr and shared_ptr are defined
#include <memory>
As you already knew that you need to compile with c++11 flag
g++ main.cpp -o run -std=c++11
// ^
So here what I learned in 2020 - memory.h is at /usr/include AND in /usr/include/c++/4.8.5 and you need the second to be found before the first.
In Eclipse set the order using Project->Properties->Path and Symbols->Includes->Add... path if needed and set first
You need to include #include that will solve the problem, at least on my ubunto linux machine