Segmentation fault with C++ and consteval - c++

The following small example of C++20 code gives a segmentation fault when run. Why?
If I create an object of class Implementation and call the consteval function implementation.foo() it returns 42 as expected. However if I create a reference of type Interface and call the consteval function interface.foo() I get a segmentation fault. I am missing something in why this would happen.
// Compile with
//
// g++ -std=c++20 -Werror -Wall -Wextra -Wpedantic consteval.cpp -o consteval
#include <iostream>
struct Interface
{
virtual consteval int foo(void) = 0;
};
struct Implementation final : public Interface
{
consteval int foo(void) override { return 42; }
};
int main(void)
{
Implementation implementation;
std::cout << "implementation.foo() returns: " << implementation.foo() << std::endl;
Interface& interface = implementation;
std::cout << "interface.foo() returns: " << interface.foo() << std::endl;
return 0;
}
Link to Compiler Explorer

Your code should not compile. I believe it is a bug in GCC that it tries to compile it and the weird segfault is just a consequence.
foo is consteval, so every usage of it must be part of a constant expression. But here you use it as interface.foo(), where interface is not a core constant expression (and foo is not static), so interface.foo() can't possibly be a constant expression. Thus your code is invalid and should simply fail with a compiler error (but should neither segfault nor "work" as it did in the comments; that's just GCC's fault).
If you correct the code to make the call valid, then you should get the right result. You could, say, wrap the thing in a constexpr function
consteval int example() {
Implementation impl;
Interface &intf = impl;
return intf.foo();
}
int main() { std::cout << example() << "\n"; }
This works fine on current GCC.
Another way to get to correct code is to make the Implementation object constexpr static and foo const-qualified:
struct Interface {
virtual consteval int foo(void) const = 0; // constexpr objects are const, so need const-qual to call foo
};
struct Implementation final : public Interface {
consteval int foo(void) const override { return 42; }
};
int main() {
constexpr static Implementation impl; // need static to form constant expression references ("the address of impl is now constexpr")
Interface const &intf = impl; // this reference is automatically usable in constant expressions (being of reference type and constant-initialized), note that it is to a *const* Interface, requiring the change to foo
std::cout << intf.foo() << "\n";
}
GCC still chokes on this one and produces a segfault, but Clang produces the expected result. Again, I suspect a GCC bug.

Related

Virtual methods with deduced return type in G++

There is a nice question explaining why virtual functions cannot use return type deduction: Why can't virtual functions use return type deduction?
Surprisingly it appears that GCC allows such possibility (as a language extension). For example, this program is accepted by GCC:
#include <iostream>
struct A {
virtual auto f() -> auto { return 1; }
};
struct B: A {
virtual auto f() -> auto override { return 2.5; }
};
int main() {
B b;
A & a = b;
std::cout << b.A::f() << ' ' << b.f() << ' ' << a.f();
}
Demo: https://gcc.godbolt.org/z/n3ejPshe7
I guess that GCC is wrong here at least with pedantic flags -std=c++20 -Wall -Wextra -pedantic-errors where all extensions must be turned off.
But the question is about the program output, which is 1 2.5 0. Since expressions a.f() and b.f() are evaluated to distinct values then struct B actually has two different virtual functions despite of override keyword, which looks as a bug.

Templates with generic classes [duplicate]

I have a class with two constructors, one that takes no arguments and one that takes one argument.
Creating objects using the constructor that takes one argument works as expected. However, if I create objects using the constructor that takes no arguments, I get an error.
For instance, if I compile this code (using g++ 4.0.1)...
class Foo
{
public:
Foo() {};
Foo(int a) {};
void bar() {};
};
int main()
{
// this works...
Foo foo1(1);
foo1.bar();
// this does not...
Foo foo2();
foo2.bar();
return 0;
}
... I get the following error:
nonclass.cpp: In function ‘int main(int, const char**)’:
nonclass.cpp:17: error: request for member ‘bar’ in ‘foo2’, which is of non-class type ‘Foo ()()’
Why is this, and how do I make it work?
Foo foo2();
change to
Foo foo2;
You get the error because compiler thinks of
Foo foo2()
as of function declaration with name 'foo2' and the return type 'Foo'.
But in that case If we change to Foo foo2 , the compiler might show the error " call of overloaded ‘Foo()’ is ambiguous".
Just for the record..
It is actually not a solution to your code, but I had the same error message when incorrectly accessing the method of a class instance pointed to by myPointerToClass, e.g.
MyClass* myPointerToClass = new MyClass();
myPointerToClass.aMethodOfThatClass();
where
myPointerToClass->aMethodOfThatClass();
would obviously be correct.
Parenthesis is not required to instantiate a class object when you don't intend to use a parameterised constructor.
Just use Foo foo2;
It will work.
Adding to the knowledge base, I got the same error for
if(class_iter->num == *int_iter)
Even though the IDE gave me the correct members for class_iter. Obviously, the problem is that "anything"::iterator doesn't have a member called num so I need to dereference it. Which doesn't work like this:
if(*class_iter->num == *int_iter)
...apparently. I eventually solved it with this:
if((*class_iter)->num == *int_iter)
I hope this helps someone who runs across this question the way I did.
I was having a similar error, it seems that the compiler misunderstand the call to the constructor without arguments. I made it work by removing the parenthesis from the variable declaration, in your code something like this:
class Foo
{
public:
Foo() {};
Foo(int a) {};
void bar() {};
};
int main()
{
// this works...
Foo foo1(1);
foo1.bar();
// this does not...
Foo foo2; // Without "()"
foo2.bar();
return 0;
}
I ran into a case where I got that error message and had
Foo foo(Bar());
and was basically trying to pass in a temporary Bar object to the Foo constructor. Turns out the compiler was translating this to
Foo foo(Bar(*)());
that is, a function declaration whose name is foo that returns a Foo that takes in an argument -- a function pointer returning a Bar with 0 arguments. When passing in temporaries like this, better to use Bar{} instead of Bar() to eliminate ambiguity.
If you want to declare a new substance with no parameter (knowing that the object have default parameters) don't write
type substance1();
but
type substance;
Certainly a corner case for this error, but I received it in a different situation, when attempting to overload the assignment operator=. It was a bit cryptic IMO (from g++ 8.1.1).
#include <cstdint>
enum DataType
{
DT_INT32,
DT_FLOAT
};
struct PrimitiveData
{
union MyData
{
int32_t i;
float f;
} data;
enum DataType dt;
template<typename T>
void operator=(T data)
{
switch(dt)
{
case DT_INT32:
{
data.i = data;
break;
}
case DT_FLOAT:
{
data.f = data;
break;
}
default:
{
break;
}
}
}
};
int main()
{
struct PrimitiveData pd;
pd.dt = DT_FLOAT;
pd = 3.4f;
return 0;
}
I received 2 "identical" errors
error: request for member ‘i’ [and 'f'] in ‘data’, which is of non-class type ‘float’
(The equivalent error for clang is:
error: member reference base type 'float' is not a structure or union)
for the lines data.i = data; and data.f = data;. Turns out the compiler was confusing local variable name 'data' and my member variable data. When I changed this to void operator=(T newData) and data.i = newData;, data.f = newData;, the error went away.
#MykolaGolubyev has already given wonderful explanation. I was looking for a solution to do somthing like this MyClass obj ( MyAnotherClass() ) but the compiler was interpreting it as a function declaration.
C++11 has braced-init-list. Using this we can do something like this
Temp t{String()};
However, this:
Temp t(String());
throws compilation error as it considers t as of type Temp(String (*)()).
#include <iostream>
class String {
public:
String(const char* str): ptr(str)
{
std::cout << "Constructor: " << str << std::endl;
}
String(void): ptr(nullptr)
{
std::cout << "Constructor" << std::endl;
}
virtual ~String(void)
{
std::cout << "Destructor" << std::endl;
}
private:
const char *ptr;
};
class Temp {
public:
Temp(String in): str(in)
{
std::cout << "Temp Constructor" << std::endl;
}
Temp(): str(String("hello"))
{
std::cout << "Temp Constructor: 2" << std::endl;
}
virtual ~Temp(void)
{
std::cout << "Temp Destructor" << std::endl;
}
virtual String get_str()
{
return str;
}
private:
String str;
};
int main(void)
{
Temp t{String()}; // Compiles Success!
// Temp t(String()); // Doesn't compile. Considers "t" as of type: Temp(String (*)())
t.get_str(); // dummy statement just to check if we are able to access the member
return 0;
}

Compiler warning for mixed array and polymorphism

In More Effective C++, an interesting point brought up is that mixing array's and polymorphism is a bad idea. For eg:
class Base {
public:
Base(int y) : a(y) {}
int a;
};
class D : public Base {
public:
D(int w, int y) : Base(y), c(w) {}
int c;
};
std::ostream& operator<<(std::ostream& os, const Base &obj )
{
os << obj.a << std::endl;
return os;
}
// This function will work perfectly well if i pass in a `Base` array,
// but if i pass in `D` array we are going to run into some problems.
// Namely that `arr[i+1] = &arr[i] + sizeof(Base)` will not progress
// the array correctly for a `D` array.
void printArray(const Base arr[]) {
for (int i = 0; i < 5; ++i) {
std::cout << arr[i];
}
}
int main() {
D arr[5] = { D(0, 10), D(1, 11), D(2, 12), D(3, 13), D(4, 14)};
printArray(arr); // This compiles without complaint! I understand that the
// conversion is legal, but it seems like a warning
// about this would be a good idea.
}
Note: I know this is bad design but is to illustrate a point.
The problem here is that when mixing these two in the way i have above, when we iterate through the array to print we will not progress the element of the array by the correct amount (ie we move by sizeof(Base) instead of sizeof(D)). This results in the output:
10
0
11
1
12
[Live example.]
(And i am guessing that calling the operator<< like this is probably UB).
When compiling with g++ -std=c++1y -Wall -Weffc++ -pedantic main.cpp I get no warnings or errors.
Is there a compiler flag that I can enable that indicates a warning in this scenario?
If not, why not?
A compiler could do a lot of static analyzing, and could know that the pointer arr in the function is used as an array with unexpected results.
However, doing that is slow and uses a lot (more) of memory, and programmers are generally impatient and want their compilations to be done as quick as possible using as little other resources as possible too. Therefore most compilers only do static analyzes that are relatively quick and easy, leaving the hard work to dedicated static analyzers.
void printArray(const Base arr[]) is equivalent to void printArray(const Base* arr).
It's legal to pass a pointer of type D to a function whose parameter is of type const Base*. So the compiler won't give any warnings.
FYI, mixing arrays and polymorphism can be done if the polymorphism is provided as an implementation detail of a handle class:
#include <iostream>
#include <vector>
// a handle which will happily own any class which implements the concept
struct Thing
{
struct concept
{
virtual void sayHello() const = 0;
virtual ~concept() = default;
};
Thing(std::unique_ptr<concept> ptr) : _impl(std::move(ptr)) {}
void sayHello() const { _impl->sayHello(); }
std::unique_ptr<concept> _impl;
};
struct thing_a : Thing::concept
{
void sayHello() const override { std::cout << "hello from A\n"; }
};
struct thing_b : Thing::concept
{
void sayHello() const override { std::cout << "hello from B\n"; }
};
int main()
{
std::vector<Thing> things;
things.emplace_back(std::make_unique<thing_a>());
things.emplace_back(std::make_unique<thing_b>());
for (const auto& t : things) { t.sayHello(); }
}
expected output:
hello from A
hello from B

For what reason I get the "request for member ... in ... which is of non-class type ..." error in this case? [duplicate]

I have a class with two constructors, one that takes no arguments and one that takes one argument.
Creating objects using the constructor that takes one argument works as expected. However, if I create objects using the constructor that takes no arguments, I get an error.
For instance, if I compile this code (using g++ 4.0.1)...
class Foo
{
public:
Foo() {};
Foo(int a) {};
void bar() {};
};
int main()
{
// this works...
Foo foo1(1);
foo1.bar();
// this does not...
Foo foo2();
foo2.bar();
return 0;
}
... I get the following error:
nonclass.cpp: In function ‘int main(int, const char**)’:
nonclass.cpp:17: error: request for member ‘bar’ in ‘foo2’, which is of non-class type ‘Foo ()()’
Why is this, and how do I make it work?
Foo foo2();
change to
Foo foo2;
You get the error because compiler thinks of
Foo foo2()
as of function declaration with name 'foo2' and the return type 'Foo'.
But in that case If we change to Foo foo2 , the compiler might show the error " call of overloaded ‘Foo()’ is ambiguous".
Just for the record..
It is actually not a solution to your code, but I had the same error message when incorrectly accessing the method of a class instance pointed to by myPointerToClass, e.g.
MyClass* myPointerToClass = new MyClass();
myPointerToClass.aMethodOfThatClass();
where
myPointerToClass->aMethodOfThatClass();
would obviously be correct.
Parenthesis is not required to instantiate a class object when you don't intend to use a parameterised constructor.
Just use Foo foo2;
It will work.
Adding to the knowledge base, I got the same error for
if(class_iter->num == *int_iter)
Even though the IDE gave me the correct members for class_iter. Obviously, the problem is that "anything"::iterator doesn't have a member called num so I need to dereference it. Which doesn't work like this:
if(*class_iter->num == *int_iter)
...apparently. I eventually solved it with this:
if((*class_iter)->num == *int_iter)
I hope this helps someone who runs across this question the way I did.
I was having a similar error, it seems that the compiler misunderstand the call to the constructor without arguments. I made it work by removing the parenthesis from the variable declaration, in your code something like this:
class Foo
{
public:
Foo() {};
Foo(int a) {};
void bar() {};
};
int main()
{
// this works...
Foo foo1(1);
foo1.bar();
// this does not...
Foo foo2; // Without "()"
foo2.bar();
return 0;
}
I ran into a case where I got that error message and had
Foo foo(Bar());
and was basically trying to pass in a temporary Bar object to the Foo constructor. Turns out the compiler was translating this to
Foo foo(Bar(*)());
that is, a function declaration whose name is foo that returns a Foo that takes in an argument -- a function pointer returning a Bar with 0 arguments. When passing in temporaries like this, better to use Bar{} instead of Bar() to eliminate ambiguity.
If you want to declare a new substance with no parameter (knowing that the object have default parameters) don't write
type substance1();
but
type substance;
Certainly a corner case for this error, but I received it in a different situation, when attempting to overload the assignment operator=. It was a bit cryptic IMO (from g++ 8.1.1).
#include <cstdint>
enum DataType
{
DT_INT32,
DT_FLOAT
};
struct PrimitiveData
{
union MyData
{
int32_t i;
float f;
} data;
enum DataType dt;
template<typename T>
void operator=(T data)
{
switch(dt)
{
case DT_INT32:
{
data.i = data;
break;
}
case DT_FLOAT:
{
data.f = data;
break;
}
default:
{
break;
}
}
}
};
int main()
{
struct PrimitiveData pd;
pd.dt = DT_FLOAT;
pd = 3.4f;
return 0;
}
I received 2 "identical" errors
error: request for member ‘i’ [and 'f'] in ‘data’, which is of non-class type ‘float’
(The equivalent error for clang is:
error: member reference base type 'float' is not a structure or union)
for the lines data.i = data; and data.f = data;. Turns out the compiler was confusing local variable name 'data' and my member variable data. When I changed this to void operator=(T newData) and data.i = newData;, data.f = newData;, the error went away.
#MykolaGolubyev has already given wonderful explanation. I was looking for a solution to do somthing like this MyClass obj ( MyAnotherClass() ) but the compiler was interpreting it as a function declaration.
C++11 has braced-init-list. Using this we can do something like this
Temp t{String()};
However, this:
Temp t(String());
throws compilation error as it considers t as of type Temp(String (*)()).
#include <iostream>
class String {
public:
String(const char* str): ptr(str)
{
std::cout << "Constructor: " << str << std::endl;
}
String(void): ptr(nullptr)
{
std::cout << "Constructor" << std::endl;
}
virtual ~String(void)
{
std::cout << "Destructor" << std::endl;
}
private:
const char *ptr;
};
class Temp {
public:
Temp(String in): str(in)
{
std::cout << "Temp Constructor" << std::endl;
}
Temp(): str(String("hello"))
{
std::cout << "Temp Constructor: 2" << std::endl;
}
virtual ~Temp(void)
{
std::cout << "Temp Destructor" << std::endl;
}
virtual String get_str()
{
return str;
}
private:
String str;
};
int main(void)
{
Temp t{String()}; // Compiles Success!
// Temp t(String()); // Doesn't compile. Considers "t" as of type: Temp(String (*)())
t.get_str(); // dummy statement just to check if we are able to access the member
return 0;
}

C++ tokenizing madness with templates and virtual functions

During refactoring of a rather large code-base my compiler came up with a great way to misunderstand me. This is a minimal example of what I am talking about:
#include <iostream>
class Foo {
public:
virtual int get() = 0;
template <typename T> int get(int i) { return 4 + i; }
};
class Bar : public Foo {
public:
virtual int get() { return 3; }
};
int main(int argv, char **argc) {
Bar b;
std::cout << b.get<char>(7) << std::endl;
return 0;
}
Clang 3.6, gcc 4.7, gcc 4.8 and gcc 4.9 all tokenize the "b.get(7)" as a comparison operator between "b.get" and "char".
template-test.cpp: In function ‘int main(int, char**)’:
template-test.cpp:16:17: error: invalid use of non-static member function
std::cout << b.get<char>(7) << std::endl;
^
template-test.cpp:16:21: error: expected primary-expression before ‘char’
std::cout << b.get<char>(7) << std::endl;
^
(This is gcc 4.9, the others say something similar)
Is this supposed to work?
The work-around I found was to declare the templated "get" in both the base and the derived class.
The name get in the derived class hides the name get in the base class. Hence, the function template get() is not found when performing name lookup, and the compiler can only interpret those tokens the way you've seen.
You can use a using declaration in your Bar class to fix that:
class Bar : public Foo {
public:
using Foo::get;
// ^^^^^^^^^^^^^^^
virtual int get() { return 3; }
};
Here is a live demo on Coliru.
If you cannot modify the definition of Bar because it is not under your control, I guess you could qualify the call to get():
std::cout << f.Foo::get<char>(7) << std::endl; // get() template is found now.
See here for a live demo. Another option is to perform the call through a pointer or reference to Foo:
Bar b;
Foo& f = b;
std::cout << f.get<char>(7) << std::endl; // get() template is found now.
Once again, live example.