Should exceptions thrown from class member initializers call std::terminate()? - c++

Given this code:
struct A {
A(int e) { throw e; }
};
struct B {
A a{42}; // Same with = 42; syntax
};
int main() {
try {
B b;
} catch (int const e) {
return e;
}
}
When compiled with GCC (versions 4.7.4, 4.8.5, 4.9.3, 5.4.0, 6.3.0):
$ g++ -std=c++11 test.cpp -o test; ./test ; echo $?
terminate called after throwing an instance of 'int'
Aborted
134
But when compiled with Clang (version 4.0.0):
$ clang++ -std=c++11 test.cpp -o test; ./test ; echo $?
42
Which behavior is correct?

This is a bug in GCC (Bug 80683).
If the constructor is the first op in the try/catch clause, then the compiler considered it as being outside of it although it should include it.
For example, the following works just fine:
#include <iostream>
struct A {
A(int e) { throw e; }
};
struct B {
A a{42}; // Same with = 42; syntax
};
int main() {
try {
// The following forces the compiler to put B's contructor inside the try/catch.
std::cout << "Welcome" << std::endl;
B b;
} catch (int e) {
std::cout << "ERROR: " << e << std::endl; // This is just for debugging
}
return 0;
}
Running:
g++ -std=c++11 test.cpp -DNDEBUG -o test; ./test ; echo $?
Outputs:
Welcome
ERROR: 42
0
My guess is that is that due to compiler optimization, it moves the constructor to the beginning of the main function. It assumes that the struct B has no constructor, then it assumes that it would never throw an exception, thus it is safe to move it outside of the try/catch clause.
If we will change the declaration of struct B to explicitly use struct A constructor:
struct B {
B():a(42) {}
A a;
};
Then the result will be as expected and we will enter the try/catch, even when removing the "Welcome" printout:
ERROR: 42
0

Clang is correct. References about that can be found in C++ standard reference draft n4296 (emphasize mine):
15.3 Handling an exception [except.handle]
...3 A handler is a match for an exception object of type E if
(3.1) — The handler is of type cv T or cv T& and E and T are the same type (ignoring the top-level cv-qualifiers),
Here an int is thrown, and the handler declares a const int. There is a match and the handler shall be invoked.

Related

G++ command throws "expected '(' for function-style cast or type construction"

Function foo takes a vector of strings. It's defined as
bool foo(vector<string>& input);
When I call foo with:
foo(vector<string>{"abc"});
my compiler gives the following error:
error: expected '(' for function-style cast or type construction
and points to { as the start of the error. This compiles fine in Xcode but I get the error when running the following via command line with:
g++ -o -std=c++17 main.cpp
What is wrong with my g++ syntax?
G++ Version Information:
g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.3 (clang-1103.0.32.59)
Target: x86_64-apple-darwin19.4.0
Thread model: posix
Your command line specifies that the output file ("-o") should be called "-std=c++17" – it does not say anything about the language version, so you're compiling as C++03.
Remove the "-o" or add an actual file name.
Also, note that your "g++" is an alias for clang.
I took your code and tried to compile it. For me there was rather problem with trying to pass non const value to function. I changed function argument to const and it compiled and printed without any problem.
#include <iostream>
#include <vector>
bool foo(const std::vector<std::string>& v) {
for (auto& a : v) { std::cout << a << std::endl; }
return true;
}
int main()
{
bool result = foo(std::vector<std::string> {"1", "2", "3" });
// do something with result
return 0;
}
Compiled on: https://www.onlinegdb.com/online_c++_compiler
Function foo expects for an l-value.
You are generating an instance and passing it to the function. But lifetime of the object is not enough for the pass-by-reference call.
Here is an example below; instance of class A is immediately destructed.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class A {
public:
A(int m): m(m) {
cerr << __func__ << endl;
}
~A() {
cerr << __func__ << endl;
}
int m;
};
int main() {
cerr << __func__ << endl;
A(5);
cerr << __func__ << endl;
return 0;
}
Outputs:
main
A
~A
main

Constructor with mis-typed default value raises no error with GCC 7

In the following code, the variable definition B<int, int>(14); should be erroneous:
#include <iostream>
struct A {
};
template<class T, class R=A>
class B {
public:
explicit B(const int s, R n = A()) {
std::cout << "c\n";
}
};
template <class T, class R=A>
void foo(const int s, R nx = A()) {};
int main() {
B<int, int>(14);
// foo<int, int>(14);
// error: could not convert ‘A()’ from ‘A’ to ‘int’
}
Why does it cause no compilation error?
I compiled the code with gcc 7.3 and g++ -std=c++17
When I compile the code with gcc 7.3 and g++ -std=c++14, I get an error.
I thought that line uses the default value for parameter n in constructor of B.
The default value of n is A(), which is not convertible to an int.
And I should get a compilation error. But that is not the case.
The similar case for function (as tested by foo) would cause compilation error.
You have run into GCC bug #83020. Clang 6 and GCC 8 (as well as GCC 6) correctly reject your example code, as does GCC 7 in C++14 mode.

constexpr (but not really) constructor compiles in gcc but not in clang

I was playing around with constexpr constructors in C++14 and above and noticed something strange. Here is my code:
#include <iostream>
#include <string>
using std::cout;
using std::endl;
#define PFN(x) cout << x << __PRETTY_FUNCTION__ << endl
#define PF PFN("")
#define NL cout << endl
struct A {
constexpr A() { PF; }
virtual ~A() { PF; NL; }
};
struct B : A {
constexpr B() { PFN(" "); }
virtual ~B() { PFN(" "); }
};
int main(int argc, char** argv) {
{ A a; }
{ B b; }
A* a = new B;
delete a;
return 0;
}
Simple enough example. I compiled it with g++ -std=c++14 -o cx_test cx_test.cpp, expecting it to give me a compile error (because I am using cout and the stream operator to print the function's name. But, to my surprise, it compiled! When I ran it, it gave the following output:
$> g++ -std=c++14 -o cx_test cx_test.cpp && ./cx_test
constexpr A::A()
virtual A::~A()
constexpr A::A()
constexpr B::B()
virtual B::~B()
virtual A::~A()
constexpr A::A()
constexpr B::B()
virtual B::~B()
virtual A::~A()
$>
But, when I compile with clang, I get:
$> clang++ -std=c++14 -o cx_test cx_test.cpp && ./cx_test
cx_test.cpp:12:15: error: constexpr constructor never produces a constant expression [-Winvalid-constexpr]
constexpr A() { PF; }
^
cx_test.cpp:12:21: note: non-constexpr function 'operator<<<std::char_traits<char> >' cannot be used in a constant expression
constexpr A() { PF; }
^
cx_test.cpp:9:12: note: expanded from macro 'PF'
#define PF PFN("")
^
cx_test.cpp:8:26: note: expanded from macro 'PFN'
#define PFN(x) cout << x << __PRETTY_FUNCTION__ << endl
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/ostream:556:5: note: declared here
operator<<(basic_ostream<char, _Traits>& __out, const char* __s)
^
1 error generated.
$>
This seems like a bug with g++ because the constructor appears to violate the restrictions of constexpr, but I am not quite sure. Which compiler is correct?
Here is the g++ version and here is the clang version (on ideone).
Both gcc and clang are correct, your program is ill-formed no diagnostic required since there is no way to invoke the constructors such that they could be evaluated as a sub-expression of a core constant expression.
From [dcl.constexpr]p5:
For a non-template, non-defaulted constexpr function or a
non-template, non-defaulted, non-inheriting constexpr constructor, if
no argument values exist such that an invocation of the function or
constructor could be an evaluated subexpression of a core constant
expression ([expr.const]), the program is ill-formed; no diagnostic
required. [ Example:
constexpr int f(bool b)
{ return b ? throw 0 : 0; } // OK
constexpr int f() { return f(true); } // ill-formed, no diagnostic required
struct B {
constexpr B(int x) : i(0) { } // x is unused
int i;
};
int global;
struct D : B {
constexpr D() : B(global) { } // ill-formed, no diagnostic required
// lvalue-to-rvalue conversion on non-constant global
};
— end example ]
If we force the constructor to be evaluated in a constant expression context then you will receive a diagnostic from gcc as well (see it live):
{ constexpr A a; }

Clang static parameter to std::fill causing linker to fail

Using Clang++ (v3.8.0), the following code fails to link due to sSomeValue being an undefined reference.
#include <iostream>
struct MyClass
{
static constexpr int sSomeSize = 3;
static constexpr int sSomeValue = 10;
};
int foo()
{
int someArray[MyClass::sSomeSize] = {};
std::fill(std::begin(someArray), std::end(someArray), MyClass::sSomeValue);
return someArray[0];
}
int main()
{
std::cout << foo() << std::endl;
}
More precisely:
clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
/tmp/main-c8de0c.o: In function `foo()':
main.cpp:(.text+0x2): undefined reference to `MyClass::sSomeValue'
/tmp/main-c8de0c.o: In function `main':
main.cpp:(.text+0x16): undefined reference to `MyClass::sSomeValue'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
However, changing the definition of foo to
int foo()
{
int someArray[MyClass::sSomeSize] = {MyClass::sSomeValue, MyClass::sSomeValue, MyClass::sSomeValue};
return someArray[0];
}
does not exhibit the same linker error, even though sSomeValue is still being used.
What is going on here? Is the compiler doing some optimization around the std::fill call that I may not be aware of?
Note that g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out compiles, links, and outputs 10 as expected with v6.3.0.
The error is nothing to do with std::fill.
If you refer below documentation, it says: Reference variables can be declared constexpr (their initializers have to be reference constant expressions):
http://en.cppreference.com/w/cpp/language/constexpr
Slight modification of your code works fine. Just make the struct variables "const &" as said above.
#include <iostream>
struct MyClass
{
static constexpr int const& sSomeSize = 3;
static constexpr int const& sSomeValue = 10;
};
int foo()
{
int someArray[MyClass::sSomeSize] = {};
std::fill(std::begin(someArray), std::end(someArray), MyClass::sSomeValue);
return someArray[0];
}
int main()
{
std::cout << foo() << std::endl;
}
Also refer here for well explained article about constexpr and static
"Does static constexpr variable make sense?
Specially the last para in ticked answer.

How to force compiler to set a non-zero value to uninitialized variables?

I am playing with C++ value initialization.
Therefore, I am printing uninitialized values in order to highlight (un)initialization depending on C++ standard version.
But uninitialized values convey often the zero value :-(
How to highlight if a variable has not been initialized?
(i.e., How to say to the compiler to use a specific value for uninitialized variables?)
Maybe this could be done using a magic user-provided allocator...
EDIT: My below snippets is not for production. I just wanted to check the implementation (by the compiler) of the C++ Standard about uninitialization/value-initialization/zero-initialization/default-initialization mechanisms. I do not want compiler warnings about uninitialized variables. I do not want to use MemoryCheckers. I just want to highlight that compiler zero-initializes some variables, default-initializes some other variables and does not initialize at all other variables. And this initialization behavior also depends on the version of C++ Standard. If you think the best way is to use compilers warnings or MemoryCheckers, please provide an answer using the below snippets.
Please do not read below detailed attempts if you have already understood my question.
You can build/run my first snippet on Coliru
#include <iostream>
struct A {
A() {} // user-defined default ctor does not initialize i
int i;
};
struct B {
A a;
};
int main()
{
std::cout << B().a.i << '\n';
// Results: C++03 -> uninitialized
// C++11 -> zero-initialized
std::cout << B{}.a.i << '\n';
// Results: C++03 -> Do not compile - B{} is correct since C++11
// C++11 -> uninitialized because
// DR1301 defines B{} as an aggregate-initialization
} // => A is value-initialized using the user-defined ctor
When compiled using -std=c++03 the execute may probably prints a zero value but I would prefer a non-zero value.
0
Possible output using -std=c++11
0
1208617840
Another possible output using -std=c++11
0
-201855824
But my more advanced snippet has now zero-values for uninitialized object B{}.a.i :-(
#include <iostream>
struct A {
A() {} // user-defined ctor does not initialize i
int i;
};
struct B {
A a;
};
int main()
{
std::cout <<"-----------"<< __cplusplus <<"-----------" "\n";
std::cout <<"B().a.i = "<< B().a.i <<'\n';
std::cout <<"B{}.a.i = "<< B{}.a.i <<'\n';
int d;
d = 42;
std::cout <<"(new(&d) B )->a.i = "<< (new(&d) B )->a.i <<'\n';
d = 42;
std::cout <<"(new(&d) B())->a.i = "<< (new(&d) B())->a.i <<'\n';
d = 42;
std::cout <<"(new(&d) B{})->a.i = "<< (new(&d) B{})->a.i <<'\n';
}
Build/Run output:
> g++ -std=c++03 -Wall -Wextra -pedantic main.cpp && ./a.out
-----------199711-----------
B().a.i = 0
(new(&d) B )->a.i = 42
(new(&d) B())->a.i = 0
> g++ -std=c++11 -Wall -Wextra -pedantic main.cpp && ./a.out
-----------201103-----------
B().a.i = 0
B{}.a.i = 0
(new(&d) B )->a.i = 42
(new(&d) B())->a.i = 0
(new(&d) B{})->a.i = 0
> g++ -std=c++14 -Wall -Wextra -pedantic main.cpp && ./a.out
-----------201402-----------
B().a.i = 0
B{}.a.i = 0
(new(&d) B )->a.i = 42
(new(&d) B())->a.i = 0
(new(&d) B{})->a.i = 0
One possible solution is to use clang++ instead of g++.
clang++ v3.7 has highlighted uninitialized values in my specific case.
Note: This answer is based on C++ value initialization that has changed since C++11. Value initialization is when parentheses/braces are empty: T(); T{}; new T(); new T{};
Build/Run below snippet on Coliru
#include <iostream>
struct A
{
A() {} // ctor does not initialize 'i'
int i;
};
struct B // implicit ctor
{
A a;
int i;
void set() { a.i = i = 42; }
};
std::ostream& operator<< (std::ostream& os, const B& b)
{ os <<'\t'<< b.a.i <<'\t'<< b.i; return os; }
int main()
{
std::cout <<"----------"<< __cplusplus <<"----------" "\n";
B b; // used to reset memory for 'placement new'
b.set(); std::cout <<"new(&b)B "<< *new(&b)B <<'\n'; // All uninitialized (in all C++ standards)
std::cout <<" B() "<< B() <<'\n'; // B::A::i uninitialized in C++03, zero-initialized in C++11
b.set(); std::cout <<"new(&b)B() "<< *new(&b)B() <<'\n'; // B::i zero-initialized (in all C++ standards)
#if __cplusplus > 2011*100 // B{} is aggregate-initialization (DR1301)
std::cout <<" B{} "<< B{} <<'\n'; // => B::A::i value-initialized
b.set(); std::cout <<"new(&b)B{} "<< *new(&b)B{} <<'\n'; // => B::i zero-initialized
#endif
}
Build output & Possible run output
> clang++ --version
clang version 3.7.0 (tags/RELEASE_370/final 246979)
Target: x86_64-unknown-linux-gnu
Thread model: posix
> clang++ -std=c++03 -Wall -Wextra -pedantic main.cpp && ./a.out
----------199711----------
new(&b)B 42 42
B() 0 0
new(&b)B() 0 0
> clang++ -std=c++11 -Wall -Wextra -pedantic main.cpp && ./a.out
----------201103----------
new(&b)B 42 42
B() 0 0
new(&b)B() 0 0
B{} 4196348 0
new(&b)B{} 42 0
> clang++ -std=c++14 -Wall -Wextra -pedantic main.cpp && ./a.out
----------201402----------
new(&b)B 42 42
B() 0 0
new(&b)B() 0 0
B{} 4196348 0
new(&b)B{} 42 0
> clang++ -std=c++1z -Wall -Wextra -pedantic main.cpp && ./a.out
----------201406----------
new(&b)B 42 42
B() 0 0
new(&b)B() 0 0
B{} 4196348 0
new(&b)B{} 42 0