Trying to design some exception-free classes, I have an inheritance structure similar to this, but I have found the noexcept specifier to be of little to no help when working with member functions as the specifier is not scoped as being within the function.
class Base
{
protected:
Base() noexcept {}
};
class Derived : public Base
{
public:
// error: 'Base::Base()' is protected
Derived() noexcept(noexcept(Base{})) : Base{} {}
// error: 'foo' was not declared in this scope
Derived(int) noexcept(noexcept(foo())) {}
// error: invalid use of 'this' at top level
Derived(float) noexcept(noexcept(this->foo())) {}
void foo() noexcept {}
};
Demo
Is this perhaps something that is being improved in C++17? Trying to search for this has yielded no relevant results. For now I've resigned to some very ugly (and possibly incorrect) attempts such as noexcept(noexcept(static_cast<Derived*>(nullptr)->foo())), but this doesn't assist in the case of the base class constructor, which is protected.
Is it even currently possible to declare a noexcept specifier which references a protected base class method like this? noexcept(auto) might be relevant, but of course isn't possible yet. Have I overlooked anything else that would allow me to include this specifier, or do I simply have to omit it in that case?
You can work around it by using an expression where the Base constructor is in scope like this:
struct test_base : public Base {};
Derived() noexcept(noexcept(test_base())) : Base() {}
I believe the reason you cannot use Base() directly is related to this question.
The way protected access specifier works, it allows the derived class
B to access the contents of an object of base class A only when that
object of class A is a subobject of class B. That means that the only
thing you can do in your code is to access the contents of A through
B: you can access the members of A through a pointer of type B * (or a
reference of type B &). But you cannot access the same members through
a pointer of type A * (or reference A &).
It's the same as if you had a member function like this:
void badfunc()
{
B b;
}
You're trying to use Base's constructor directly instead of going through Derived. When you initialize the base in the constructor initialization list, that is a special context that allows you to call the constructor because you're doing it as part of initializing Derived.
This is really multiple questions in one.
About this...
From my understanding, the use of this is supposed to be completely superfluous but compiler support for C++11 is not entirely universal. This should work, according to the C++11 standard:
struct Base {
void func() noexcept;
};
struct Derived() {
void func() noexcept(noexcept(Base::func())) {}
};
Note that base_func() is a non-static member function, but because it appears in an "unevaluated operand" it is okay. From n3337 sec 4.1.1:
An id-expression that denotes a non-static data member or non-static member function of a class can only be used:
...
if that id-expression denotes a non-static data member and it appears in an unevaluated operand.
However, some compilers do not support this. You are then forced to use std::declval:
#include <utility>
struct Base {
void func() noexcept;
};
struct Derived() {
void func() noexcept(noexcept(std::declval<Base>().func())) {}
};
About accessibility...
I read through the relevant parts of the standard about "unevaluated operands" and "member access control" and I have come to the conclusion that the standard is a bit ambiguous. It mentions that a protected name can be used only by members, friends, and derived classes. The question is whether unevaluated operands "use" the member names which appear in them. They certainly don't odr-use the member names, and can even use member names if no definition is provided, and this kind of ambiguity is exactly why the term "odr-use" even exists! For example,
int f(); // No definition anywhere in program
int x = sizeof(f()); // Completely valid, even without definition of f
struct X {
X() = delete; // Cannot use this constructor
};
int xsize = sizeof(X{}); // Completely valid
Even though it is somewhat unclear, I have a hard time imagining that the C++ committee could have intended to let you use deleted member functions in unevaluated operands but not inaccessible member functions. However, I am not certain.
Note that the above code compiles without error both with GCC and Clang. However, the following code is does not:
class X {
X(){}
};
class Y {
Y() = delete;
};
bool xokay = noexcept(X{}); // Error!
bool yokay = noexcept(Y{}); // Ok
Both GCC and Clang accept Y but not X, which seems a bit weird to say the least. The following code is accepted by Clang but not GCC, and using std::declval does not help:
class Base {
protected:
void func();
};
class Derived : public Base {
// Clang accepts this, GCC does not.
void func2() noexcept(noexcept(Base::func())) {}
};
What a mess.
Conclusions
The conclusion here is that it seems that there is plenty of inconsistency to go around, and plenty of gaps between current compilers and the C++11 specs.
Related
I found a strange behavior running this small snippet of code compiled with clang:
#include <iostream>
#include <exception>
#include <typeinfo>
struct Foo : public std::exception {
std::string myString;
Foo(const std::string& str) : myString(str) {}
Foo() : Foo(typeid(*this).name()) {}
};
int main()
{
Foo f;
std::cout << f.myString;
}
The instruction typeid(*this).name() called inside the delegated constructor returns a nullptr that causes a segmentation fault. During the delegated constructor call std::exception base class is not yet initialized and this seems the cause of this behavior.
I'm wondering if this code is ill-formed for some reason, or this behavior is expected.
I cannot reproduce this bug with g++, where the code runs fine.
It also occurs only if the base class is std::exception, in any other case it works fine even on clang.
This has undefined behavior. typeid is allowed to be applied to the object under construction in the constructor, also the member initializer list, but only after construction of all base class subobjects has completed. See [class.base.init]/16.
If typeid(*this) was used after the base classes have been constructed, then [class.cdtor]/5 would describe the behavior of typeid in this specific situation. (It would return the type_info corresponding to Foo irregardless of whether Foo is the most-derived type.)
I think this is only supposed to apply though if *this has polymorphic type, i.e. Foo has a (inherited) virtual member function (std::exception::what and std::exception::~exception in your case). The current wording doesn't seem to clearly separate this, but for non-polymorphic types the expression shouldn't even be evaluated, so it can't matter that *this refers to the object under construction. There are related open CWG issues, e.g. CWG issue 1517.
Regardless of the semantics of typeid(*this), an alternative would be shifting more of the work to compile-time. Specifically:
Implement a constexpr function which gets you the name of a type - and I mean a proper name, not some annoying code. You can find an implementation in this SO answer.
Use the type name in the classes inheriting Foo to construct your Foo base.
You can automate this further using the CRTP and writing class MyException : Foo<MyException>, with the Foo template constructor extracting the template argument type from its own class type. And this will all happen at compile time!
The reason for UB is using the object before even its very first subobject is constructed.
In general, built-in RTTI can not be properly usef inside the constructor. Virtual functions are bound early; because virtual table only contains current class info; derived class is not constructed yet. I would put the dynamic calculations in the what virtual method:
struct Foo : public std::exception {
consteval Foo(char const * const str) : name{str} {};
consteval Foo() = default;
const char* what() const noexcept override {
return name.empty()?
typeid(*this).name():
name;
};
private:
std::string_view const name;
};
Why did the creator of C++ decide to use constructor initializer list to initialize base classes? Why didn't he instead choose to use syntax like the second comment line in the following code?
class A{
public:
A() { }
};
class B : A{
public:
B() : A() { } // Why decide to use this one, using constructor initializer, to initialize base class?
B() { A(); } // Why not choose this one? It's easy for me to understand if it was possible.
};
int main(int argc, char *argv[]){
/* do nothing */
}
The advantage of using an initializer list is, that you have a completely initialized object in the body of the constructor.
class A {
public:
A(const int val) : val(val) { }
private:
const int val;
};
class B : A{
public:
B() : A(123) {
// here A and B are already initialized
}
};
So you have a guarantee that all members, even those of the parent, are not in an undefined state.
Edit
In the example of the question it is not necessary to call the base class in the initializer list, this is done automatically. So I slightly modified the example.
I can see a few possible alternatives to the current C++ rule that base classes and data members of a class type are initialised in the mem-initialiser list of the class type's constructor(s). They all come with their set of issues, which I will discuss below.
But first, note that you cannot simply write a derived constructor like this:
struct Derived : Base
{
Derived()
{
Base(42);
}
};
and expect the line Base(42); to call the base class constructor. Everywhere else in C++, such a statement creates a temporary object of type Base initialised with 42. Changing its meaning inside a constructor (or just inside its first line?) would be a syntax nightmare.
Which means that new syntax would need to be introduced for this. In the rest of this answer, I will use a hypothetical construct __super<Base> for this.
Now on to discuss possible approaches which would be closer to your desired syntax, and present their problems.
Variant A
Base classes are initialised in the constructor body, while data members are still initialised in the mem-initialiser list. (This follows the letter of your question the closest).
The would have the immediate problem of stuff executing in different order than it's written. For very good reasons, the rule in C++ is that base class subobjects are initialised before any data members of the derived class. Imagine this use case:
struct Base
{
int m;
Base(int a) : m(a) {}
};
struct Derived
{
int x;
Derived() :
x(42)
{
__super<Base>(x);
}
};
Written like this, you could easily assume x would be initialised first and then Base would be initialised with 42. However, that would not be the case and instead reading x would be undefined.
Variant B
Mem-initialiser lists are removed altogether, base classes are initialised using __super, and data members are simply assigned in the constructor body (pretty much the way Java does it).
This cannot work in C++ because initialisation and assignment are fundamentally different concepts. There are types where the two operations do vastly different things (e.g. references), and types which are not assignable at all (e.g. std::mutex).
How would this approach deal with a situtation like this?
struct Base
{
int m;
Base(int a) : { m = a; }
};
struct Derived : Base
{
double &r;
Derived(int x, double *pd)
{
__super<Base>(x); // This one's OK
r = *pd; // PROBLEM
}
};
Consider the line marked // PROBLEM. Either it means what it normally does in C++ (in which case it assigns a double into a "random place" which the uninitialised reference r references), or we change its semantics in constructors (or just in initial parts of a constructor?) to do initialisation instead of assignment. The former gives us a buggy program while the latter introduces totally chaotic syntax and unreadable code.
Variant C
Like B above, but introduce special syntax for initialising a data member in the constructor body (like we did with __super). Something like __init_mem:
struct Base
{
int m;
Base(int a) : { __init_mem(m, a); }
};
struct Derived : Base
{
double &r;
Derived(int x, double *pd)
{
__super<Base>(x);
__init_mem(r, *pd);
}
};
Now, the question is, what have we achieved? Previously, we had the mem-initialiser list, a special syntax to initialise bases and members. It had the advantage that it made clear these things happen first, before the constructor body starts. Now, we have a special syntax to initialise bases and members, and we need to force the programmer to put it at the start of the constructor.
Note that Java can get away with not having a mem-initialiser list for several reasons which don't apply to C++:
The syntax for creating an object is always new Type(args) in Java, whereas Type(args) can be used in C++ to construct objects by value.
Java only uses pointers, where initialisation and assignment are equivalent. For many C++ types, there operations are distinct.
Java classes can only have one base class, so using just super is enough. C++ would need to differentiate which base class you're referring to.
B() : A() { }
This will initialize the base class in user defined way.
B() { A(); }
This will NOT initialize the base class in user defined way.
This will create an object inside of constructor i.e B(){}
I think first initialization has better readability compared to the second and you can also deduce class hierarchy.
I have always been under the impression that C/C++ is parsed in 1 pass, therefore, a symbol must be declared before it can be used.
Thus this does not work:
void a()
{
b();
}
void b()
{
}
unless we forward declare void a();
However, I noticed that this does work:
class Foo
{
public:
void a()
{
b();
}
void b()
{
}
};
Why does this work? If C++ is parsed in a single pass through the code then this should not work I would think because the symbol Foo::b() has not been defined when it is called.
The definition of your class:
class Foo
{
public:
void a() { b(); }
void b() { }
};
has the same meaning than:
class Foo
{
public:
void a();
void b();
};
void Foo::a() { b(); }
void Foo::b() { }
This is why the function body sees all the members, as if the class was already completely defined. This is by the ways stated in the C++ standard:
3.3.7/1 The potential scope of a name declared in a class consists not only of the declarative region following the name’s point of declaration, but also of all function bodies,
brace-or-equal-initializers of non-static data members, and default
arguments in that class (including such things in nested classes).
The compiler still parses the file in a single pass. But the parsing the grammatical construct is only a part of the larger compilation process, in which applying the context to the parsed grammar production plays also a role (see also this SO question).
There are things called forward references (different from forward declaration)
class C
{
public:
void mutator(int x) { myValue = x; }
int accessor() const { return myValue; }
private:
int myValue;
};
here myValue is accessed before it it declared. C++ does not usually allow forward references but for class members it allows them. It is the compilers job to remember the definition of mutator and accessor until it sees myValue
On the first pass all the class interface is read and thus when the code for function a is compiled it knows that the function b exists in the class Foo
Section 3.3.7 of the C++ Standard includes, among other rules, the statement that
The potential scope of a name declared in a class consists not only of the declarative region following the name’s point of declaration, but also of all function bodies, default arguments, exception-specifications, and brace-or-equal-initializers of non-static data members in that class (including such things in nested classes).
Basically, this requires that analysis of the mentioned contexts, if they appear inline inside the class definition, is deferred until the entire class definition has been processed just as if you had used an out-of-line definition.
A related rule is found in section 9.2:
A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies,
default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise
it is regarded as incomplete within its own class member-specification.
This code is rejected by (at least) MSVC, ICC, and GCC:
class A {
public:
A( int ) { }
};
class B: virtual public A {
public:
//B(): A( -1 ) { } // uncomment to make it compilable
virtual void do_something() = 0;
};
class C: public B {
public:
C(): A( 1 ) { }
virtual void do_something() { }
};
int main() {
C c;
return 0;
}
on the basis of
error : no default constructor exists for class "A"
class B: virtual public A {
^
detected during implicit generation of "B::B()" at line 14
Questions:
If the code is indeed invalid, how exactly does this follow from
the standard? AFAICT, 10.4/2 and 1.8/4 taken together imply that B
cannot be a type of the most derived class, and therefore from
12.6.2/10 we have that B can never, ever call A's constructors.
(The section numbers are for C++11.)
If the code is valid, are compilers violating the standard by
requiring the presence of constructors they could not possibly call?
Note that not only they want to call A::A() from B::B(), but they
want to do it while compiling C::C() (double weird).
P.S. This was originally asked on the ICC forum, but posted here due to not being limited to this compiler (and no details forthcoming).
Clang shows the error as:
error: call to implicitly-deleted default constructor of 'B'
C(): A( 1 ) { }
^
12.1/5 says "A defaulted default constructor for class X is defined as deleted if [...] any [...] virtual base class [...] has class type M [...] and [...] M has no default constructor [...]."
I think you are trying to derive a "theorem" from the facts that can be found in the standard, and then you expect the standard to acknowledge the existence of that "theorem". The standard does not do that. It doesn't strive to find and incorporate all possible "theorems" that can be derived from the standard text.
Your "theorem" is perfectly valid (unless I'm missing something). You are right, since class B is abstract, this class can never be used as a most derived class. This immediately means that class B will never get a chance to construct its virtual base A. And that means that technically in B the compiler should not care about the availability, and/or accessibility of the appropriate constructors in A or in any other virtual bases.
But the standard simply does not make that connection and does not care to make it. It doesn't treat constructors of abstract classes in any special way. The requirements imposed on such constructors are the same as for non-abstract classes.
You can call try suggesting it as a possible improvement to the standard committee.
It looks like 12.6.2/4 prohibits this to me:
If a given nonstatic data member or base class is not named by a
mem-initializer-id (including the case where there is no
mem-initializer-list because the constructor has no ctor-initializer),
then
— If the entity is a nonstatic data member of (possibly
cv-qualified) class type (or array thereof) or a base class, and the
entity class is a non-POD class, the entity is default-initialized
(8.5)...
It looks to me like that regardless of the class being a virtual base, B's default constructor is still synthesized by the compiler, and such default constructor doesn't know how to construct its A base ("the entity is default-initialized (8.5)").
Is the this pointer ever required? I guess you'd need it if you were functionally passing around the instance of the class pointed to by this. But in terms of setting/retrieving/calling/whatever members, is this always optional?
I've tagged this C++ because that's the language I'm specifically wondering about, but if someone can confirm that the construct is the same for Java and other OO languages that use a this pointer, it'd be appreciated.
There's three cases I can think of:
When you simply want to pass a pointer to the current class:
class B;
struct A {
B* parent_;
A(B* parent) : parent_(parent) {}
};
struct B {
A* a;
B() : a(new A(this)) {}
};
In a constructor or member function, where a member is shadowed by an argument:
struct A {
int a;
void set_a(int a) { this->a = a; }
};
Here, the member variable "a" is shadowed by the argument "a", so this-> is used to access the member instead of the argument.
(example above edited to be a function rather than constructor, since you wouldn't normally assign this way in a constructor)
When accessing a public/protected member variable or function in a base class of a template class
template <class T>
struct A {
int a;
};
template <class T>
struct B : public A<T> {
int f() { return this->a; }
}
here, a alone would not be a dependent name, so the compiler would expect to find a declaration of it in B or a base of B that does not depend on T. Adding this-> makes the lookup dependent on the type of this, and since this is a dependent type, the lookup of a is deferred until f() is instantiated.
One could write return A::a instead of return this->a, but in the presence of multiple bases, whether direct or indirect, using this-> is more flexible. This alternative syntax is also limited to member variables and non-virtual functions - if it is used with a virtual function, it the function will be called directly instead of doing virtual function call.
You need it when you have a local variable that has the exact same name as the member variable. In this case, the local variable is said to shadow the member variable. To get to the member variable in this situation, you must use this.
Some people consider it good practice to explicitly mention that the variable you are modifying is a member variable by using this all the time, but this is not always the case.
sometimes "this" is required, maybe when you are passing your object to another function.
look at this c# code( for opening a modal form with this parent)
Form1 f = new Form();
f.ShowDialog(this);