c++11 Global initialization order and thread_local - c++

Hi when running the following using gcc 4.8.1 when using the thread_local keyword the assertion is hit. When removing the thread_local the assert is not hit. Does anyone know why this is? There is some undefined global ordering but I would expect buf_ to have a valid address before assigning ptr_. Just remove the keyword thread_local and it works for me.
Output:
$ ./ThreadLocal
Running Tester
ThreadLocal: main.cpp:13: int main(): Assertion `buf == ptr' failed.
Aborted (core dumped)
Output when removing thread_local keyword
Running Tester
Test.hpp
#include <iostream>
#include <cassert>
template <typename std::size_t N>
struct Mem
{
Mem() noexcept: ptr_(buf_)
{}
char * getBuf() { return buf_; }
char * getPtr() { return ptr_; }
private:
char buf_[N];
char * ptr_;
};
template <typename std::size_t N>
struct Tester
{
Tester()
{
std::cout << " Running Tester " << std::endl;
}
char * getPtr() { return _mem.getPtr(); }
char * getBuf() { return _mem.getBuf(); }
private:
static thread_local Mem<N> _mem;
};
main.cpp
#include <iostream>
#include "Test.hpp"
template <typename std::size_t N>
thread_local Mem<N> Tester<N>::_mem;
int main()
{
Tester<500> t;
char * ptr = t.getPtr();
char * buf = t.getBuf();
assert( buf == ptr );
}

It looks like a bug in GCC. Apparently Tester::_mem is not being initialized at all. GCC 4.9.0 does the same, but clang 3.5.0 works fine
Making _mem not dependent on template parameter makes GCC crash.
Finally, making Tester a non-template class makes GCC work at last.
Update: These seem to be known bugs in GCC.

Related

Conditional compilation (constexpr if) and "ISO C++ forbids zero-size array"

With the following code:
#include <algorithm>
constexpr int DATA_SIZE = 5;
constexpr int A_ARRAY_ALLOWED_SIZE = 5;
constexpr int A_ARRAY_SIZE = std::min(A_ARRAY_ALLOWED_SIZE, DATA_SIZE);
constexpr int B_ARRAY_SIZE = DATA_SIZE - A_ARRAY_ALLOWED_SIZE;
class A {
int a[A_ARRAY_SIZE];
};
class B {
int b[B_ARRAY_SIZE];
};
int main()
{
A a;
if constexpr (B_ARRAY_SIZE)
{
B b;
}
return 0;
}
I'm getting compiler error (with -pedantic flag) which complains that zero-size array is not allowed. In my example the object with the zero size array is never created but looks like it is still an issue.
I was trying to workaround it with usage of std::conditional but even then I ended up with an additional function like:
constexpr int Get_B_ARRAY_SIZE()
{
if (B_ARRAY_SIZE)
return B_ARRAY_SIZE;
return 1; // workaround for zero-size array
}
What is a proper way of handling such an issue?
EDIT:
I'm aware that all of if branches should contain valid code. I'm also aware that zero-size arrays are not allowed. My question is how to refactor this code to get similar behawior like when compiling without -pedantic flag. I suspect that I can use template meta programming to achieve this purpose but I'm not sure how to do it.
If you need equivalent of std::conditional, but for values, rather than types, you can do it like this:
#include <iostream>
#include <type_traits>
template<size_t N>
struct safe_array_size : std::integral_constant<size_t, N> {};
template<>
struct safe_array_size<0> : std::integral_constant<size_t, 1> {};
int main()
{
char a[safe_array_size<0>::value];
char b[safe_array_size<1>::value];
std::cout << sizeof(a) << std::endl;
std::cout << sizeof(b) << std::endl;
}
Or using std::conditional:
#include <iostream>
#include <type_traits>
template<size_t N>
constexpr size_t safe_array_size = std::conditional_t<N==0, std::integral_constant<size_t, 1>, std::integral_constant<size_t, N>>::value;
int main()
{
char a[safe_array_size<0>];
char b[safe_array_size<1>];
std::cout << sizeof(a) << std::endl;
std::cout << sizeof(b) << std::endl;
}
if constexpr (at least, how you are using it) cannot directly work around this error because it is the class definition that is ill-formed. Whether or not you instantiate the class is irrelevant. You can fix this by ensuring that the array size is never zero with std::max:
#include <algorithm>
constexpr int DATA_SIZE = 5;
constexpr int A_ARRAY_ALLOWED_SIZE = 5;
constexpr int A_ARRAY_SIZE = std::min(A_ARRAY_ALLOWED_SIZE, DATA_SIZE);
constexpr int B_ARRAY_SIZE = DATA_SIZE - A_ARRAY_ALLOWED_SIZE;
class A {
int a[A_ARRAY_SIZE];
};
class B {
int b[std::max(B_ARRAY_SIZE, 1)];
};
int main()
{
A a;
if constexpr (B_ARRAY_SIZE)
{
B b;
}
return 0;
}
Note that std::max is constexpr as of C++14. You could implement your own max function if you are on C++11.
If you need to ensure that the class is never actually instantiated unless the array size is non-zero, the if constexpr check in the above code will handle that.

ICE in clang++ with is_invocable_v / is my code valid?

The following code fails to compile with clang (core dump / ICE) - but it compiles fine with gcc and msvc.
Is my code valid? Can I change something that would work with current clang version.
#include <type_traits>
#include <iostream>
struct A {
void Func() {
}
};
struct B {
static void Func() {
std::cout << "Hello from struct \n";
}
};
template<typename T>
void Do(){
auto lambda = [](auto&& cls) -> decltype(
std::remove_const_t<std::remove_reference_t<decltype(cls)>>::Func()
) {};
if constexpr (!std::is_invocable_v<decltype(lambda), A>){
std::cout << "no static Foo\n";
} else{
T::Foo();
}
}
int main()
{
Do<A>();
Do<B>();
return 0;
}
The idea of this code is to detect if for example S::Func() is a valid expression.

How to limit char array length in constructor

Using Extended Embedded Cpp. How can I make this result in a compilation error in a release build:
Param okParam("Yeah!"); // this line should be ok
Param nOkParam("REEEEEEEEEEE"); // too big array, not ok. compiler error.
where:
int const c_max = 10;
template<int N>
struct Param
{
char value[c_max];
Param(char const (&p_value)[N])
{
memcpy(value, p_value, sizeof(p_value));
}
};
I don't think you can template the constructor, so the entire struct needs to be templated, right?
I want this to provide a clean compiler error so that the person using this will notice it immediately.
Our version of extended embedded C++ doesn't provide any stl containers, I'm not sure if it's even possible.
I'm looking for some way to make the template result in a good compilation error. Sadly I can't use boost either, since the platform would not support it.
You have basically two solutions: SFINAE (C++98) or static_assert (C++11):
SFINAE
You can provide a constructor for Param only for char arrays less than a given size long. In C++98 this looks a bit ugly, but it works:
#include <cstddef>
template<bool b>
struct enable_if {};
template<>
struct enable_if<true>
{
typedef int type;
};
template<std::size_t MAXSIZE>
struct Param
{
template<std::size_t SIZE>
explicit Param(
char const (&input) [SIZE],
std::size_t = sizeof(typename enable_if<SIZE < MAXSIZE>::type) // SFINAE at work
) { (void) input; }
};
int main()
{
// "hello": char const[6], 6 < 7, OK
Param<7> p1("hello");
// "hello world": char const[12], 12 >= 7, KO
Param<7> p2("hello world"); // ugly error here
}
Live demo
Assert (C++11 only)
Inside the constructor of Param, you can check if the supplied char array is too big and pop a readable error at compilation-time:
#include <cstddef>
#include <type_traits>
template<std::size_t MAXSIZE>
struct Param
{
template<std::size_t SIZE>
explicit Param(char const (&input) [SIZE])
{ static_assert(sizeof(input) < MAXSIZE, "input is too big."); }
};
int main()
{
// "hello": char const[6], 6 < 7, OK
Param<7> p1("hello");
// "hello world": char const[12], 12 >= 7, KO
Param<7> p2("hello world"); // "error: static assertion failed: input is too big."
}
Live demo
Probably the simplest way is to add a static_assert, using one of the old C techniques for compile-time checks if your implementation doesn't have static_assert yet:
#include <cstring>
#if __cplusplus < 201103L
#define static_assert(expr, message) \
int static_assert_(int (&static_assert_failed)[(expr)?1:-1])
#endif
template<int N>
struct Param
{
static const int c_max = 10;
static_assert(N < c_max, "Param string too long");
char value[c_max];
Param(char const (&p_value)[N])
{
std::memcpy(value, p_value, sizeof p_value);
}
};
int main()
{
Param okParam("Yeah!"); // this line should be ok
Param nOkParam("REEEEEEEEEEE"); // too big array, not ok. compiler error.
}

C++ - Strange behaviour with template parameters that are different but have same name

I ran into some strange thing with template parameters.
Basically, I have two cpp files with different structs defined in them but with the same name. (both in anonymous namespace.) When I pass the structs to a templated function, the same template instance of that function is being called. That one sees both structures as same.
I don't understand if this is a compiler bug or am I just being a newbie.
In my real-world code this lead to a nasty bug so I wrote a simple test. (I omitted the header guards here.)
SomeFunc.hpp:
template<typename T> int someFunc(const T& obj) {
return sizeof(T);
}
Test1.hpp:
int testFunc1();
Test1.cpp:
#include "Test1.hpp"
#include "SomeFunc.hpp"
struct CTestStruct{int a; int b; float c;};
int testFunc1() {
CTestStruct test_sturct;
return someFunc( test_sturct);
}
Test2.hpp:
int testFunc2();
Test2.cpp:
#include "Test2.hpp"
#include "SomeFunc.hpp"
struct CTestStruct{char a; float b;};
int testFunc2() {
CTestStruct test_sturct;
return someFunc( test_sturct);
}
Main.cpp:
#include "Test1.hpp"
#include "Test2.hpp"
int main(){
std::cout << testFunc1() << "\n";
std::cout << testFunc2() << "\n";
return 0;
}
Output:
12
12
The problem is that testFunc1 and testFunc2 see two different structures, but someFunc treats them as the same. When I modify testFunc1 to {return 0;} (so no template instance is generated for that sturct) the output is:
0
8
Compiler is GCC 7.3.0.

No ADL inside decltype on VS2012

I just realized that trying to get the return type of a function via decltype does not involve ADL (argument-dependent-lookup) on VS2012 (tested using cl.exe V17.00.60610.1).
The following example
#include <stdio.h>
#include <typeinfo>
namespace A {
int Func(void const *) {
printf("A::Func(void const *)\n");
return 0;
}
template <typename T> void Do(T const &t) {
Func(&t);
}
template <typename T> void PrintType(T const &t) {
printf("Type: %s\n", typeid(decltype(Func(&t))).name());
}
}
namespace B {
struct XX { };
float Func(XX const *) {
printf("B::Func(XX const *)\n");
return 0.0f;
}
}
int main(int argc, char **argv) {
B::XX xx;
A::Do(xx);
A::PrintType(xx);
return 0;
}
Gives
B::Func(XX const *)
Type: int
on VS2012
but (what is expected):
B::Func(XX const *)
Type: f
on gcc 4.7.3.
So ADL works when calling the function (line 1 in output) but not when used inside decltype on VS2012.
Or am I missing some different point?
A minimal test case is:
namespace N
{
struct C {};
C f(C) {};
}
N::C c1;
decltype(f(c1)) c2;
If the compiler doesn't support ADL inside decltype, then the above will not compile.
I'm told it does compile, so maybe it is the interaction between ADL and template instantiation that is the problem.
If find it amusing that the IDE/Intellisense whatsoever seems to do the lookup correctly but the compiler does not.
This example shows no intellisense errors and a is displayed to be of type size_t when hovering it.
#include <iostream>
namespace A
{
struct C {};
size_t f(C*) { return 5U; };
}
namespace B
{
void f(void *) { };
void f2 (A::C x)
{ decltype(f(&x)) a; std::cout << typeid(a).name() << std::endl; }
}
int main (void)
{
A::C c;
B::f2(c);
}
The compiler stops with Error C2182 and complains about a variable of type void.
It seems to be a problem independant of templates.