Use of this in initializer list - c++

Suppose I have a class Baz that inherits from classes Foo and Bar, in that order. The constructor for class Bar takes a pointer to a Foo object. What I would like to do is to pass this as the Foo object to the Bar constructor:
Baz () : Foo(), Bar(this) {}
A working example:
#include <iostream>
class Bar;
class Foo {
public:
virtual ~Foo() {}
virtual void parse_bar (Bar&) const = 0;
};
class Bar {
private:
const Foo * parser;
public:
Bar (const Foo * parser_in) : parser(parser_in) {}
virtual ~Bar() {}
void parse_self () { parser->parse_bar (*this); }
};
class Baz : public Foo, public Bar {
public:
Baz () : Foo(), Bar(this) {}
virtual void parse_bar (Bar &) const { std::cout << "Hello World\n"; }
};
int main () {
Baz baz;
baz.parse_self();
}
This happens to work on my computer, with my compilers (tested with a couple of them). However section 9.3.2 of the 2003 standard makes me a bit uneasy that I might just be getting lucky, that using this this way is undefined behavior. Strictly speaking, the initializer list is outside the body of the constructor. Here's the relevant text, emphasis mine:
9.3.2 The this pointer
In the body of a nonstatic member function, the keyword this is a non-lvalue expression whose value is the address of the object for which the function is called.
So is my usage legal and well-defined, or is it undefined behavior?

There are two points that have to be noted in this case.
Firstly, in the constructor initializer list this pointer refers to a non-constructed (or not-fully-constructed) object. It is OK to access such pointer, but the object it refers to can only be used in limited ways. See 12.7 in the language specification.
Secondly, in your specific example what you are actually doing is converting this pointer to Foo * type before attempting any access. This is completely safe since by that moment the Foo subobject is fully constructed. (I assume that, whatever access will follow, if any, will be restricted only to the fully constructed Foo subobject).
The only concern is this case is whether it is legal to convert this to Foo * type, i.e. whether the conversion process itself should succeed. The answer is: yes, in case of ordinary (non-virtual) inheritance such conversion is perfectly legal and safe (again, explicitly allowed in 12.7)

It is fine. The C++ standard actually clarifies the use of this pointers in initializer lists:
12.6.2 Initializing bases and members [class.base.init]
Paragraph 7: Names in the expression-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified. [Example:
class X {
int a;
int b;
int i;
int j;
public:
const int& r;
X(int i): r(a), b(i), i(i), j(this->i) {}
};
initializes X::r to refer to X::a, initializes X::b with the
value of the constructor parameter i, initializes X::i with the
value of the constructor parameter i, and initializes X::j with
the value of X::i; this takes place each time an object of class X
is created. ] [Note: because the mem-initializer are evaluated in
the scope of the constructor, the this pointer can be used in the
expression-list of a mem-initializer to refer to the object being
initialized. ]
The type of the this pointer in the initializer of Baz is in fact of type Baz. Of course, you have to be mindful of the fact that not all of the members may have been initialized. Many, if not all, compilers set at their highest warning levels (which you really should be doing anyway) will warn about you passing a this pointer to the base class.
However, it looks like you're making it more complicated that it needs to be. Why not just put the virtual function parse_bar() in the Bar class, and forget about the Foo class?
#include <iostream>
class Bar
{
public:
Bar() {}
virtual ~Bar() {}
void parse_self () { parse_bar(); }
private: // Template method pattern
virtual void parse_bar() const = 0;
};
class Baz : public Bar
{
public:
Baz () {}
private: // Yes, this does override the private `parse_bar()` member!
virtual void parse_bar() const { std::cout << "Hello World\n"; }
};
int main ()
{
Baz baz;
baz.parse_self();
}
This does essentially the same function but with less code.

Related

Method as an argument of base class constructor in subclass constructor [duplicate]

OK, member variables can be used to initialize other member variables in an initialization list (with care taken about the initialization order etc). What about member functions? To be specific, is this snippet legal according to the C++ standard?
struct foo{
foo(const size_t N) : N_(N), arr_(fill_arr(N)) {
//arr_ = fill_arr(N); // or should I fall back to this one?
}
std::vector<double> fill_arr(const size_t N){
std::vector<double> arr(N);
// fill in the vector somehow
return arr;
}
size_t N_;
std::vector<double> arr_;
// other stuff
};
Yes, your use of member function in initialization list is valid and complies with the standard.
Data members are initialized in the order of their declaration (and that's the reason why they should appear in the initialization list in the order of their declaration - the rule that you followed in your example). N_ is initialized first and you could have passed this data member to fill_arr. fill_arr is called before constructor but because this function does not access uninitialized data members (it does not access data members at all) its call is considered safe.
Here are some relevant excepts from the latest draft (N3242=11-0012) of the C++ standard:
§ 12.6.2.13: Member functions (including virtual member functions,
10.3) can be called for an object under construction.(...) However, if these operations are performed in a ctor-initializer (or in a function
called directly or indirectly from a ctor-initializer) before all the
mem-initializers for base classes have completed, the result of the
operation is undefined. Example:
class A { public: A(int); };
class B : public A {
int j;
public:
int f();
B() : A(f()), // undefined: calls member function
// but base A not yet initialized
j(f()) { } // well-defined: bases are all initialized
};
class C {
public:
C(int);
};
class D : public B, C {
int i;
public:
D() : C(f()), // undefined: calls member function
// but base C not yet initialized
i(f()) { } // well-defined: bases are all initialized
};
§12.7.1: For an object with a non-trivial constructor, referring to
any non-static member or base class of the object before the
constructor begins execution results in undefined behavior. Example
struct W { int j; };
struct X : public virtual W { };
struct Y {
int *p;
X x;
Y() : p(&x.j) { // undefined, x is not yet constructed
}
};
While initializing objects in the initialization list, the object is not yet fully constructed.
If those function tries to access the part of the object which is not yet constructed then that is a undefined behavior else its fine.
see this answer.

Pass in-class initialized const member to Base constructor?

I have a in-class initialized const member in a derived class which I'd like to pass to the constructor of the base class.
Example:
class Base{
public:
Base(int a) : i(a){}
private:
int i;
};
class Derived : Base{
public:
Derived() : Base(a){}
private:
const int a = 7;
};
int main(){
Derived d;
}
However this spawns an uninitialized error:
field 'a' is uninitialized when used here [-Wuninitialized]
I was under the impression that const initializing it would set the value directly allowing it to be passed from the derived ctor in this manner. Am I doing something wrong or am I under the wrong impression? When are the const in-class initialized members initialized?
When initializing base classes and class members during creation of an object, the order of initialization is:
Virtual base classes, in tree order
Direct non-virtual base classes, in order
Non-static data members, in their order of declaration.
So Base(a) happens before a = 7 happens.
One way to fix this would be to make a be static const or static constexpr. This is probably a good idea anyway, because non-static const variables make your class more difficult to use. (e.g. there will not be an implicitly-generated copy-constructor).
Your question,
When are the const in-class initialized members initialized?
is a bit of a red herring. "in-class initialized" doesn't really mean anything; the brace-or-equal initializer is essentially just syntactic sugar and takes the place of the corresponding constructor initalizer list slot. const also has no special bearing. So the real question should be:
When are non-static data members initialized?
The details don't actually matter so much, suffice to say that non-static data members are initialized after base subobjects are initialized, so your proposed construction cannot work.
The straight-forward answer is not to use a brace-or-equals-initializer and just use a normal (possibly defaulted) constructor parameter. Here are a few examples:
struct Foo : Base
{
const int a;
// Default constructor, mention value only once
Foo(int _a = 10) : Base(_a), a(_a) {}
// DRYolent default constructor
Foo() : Base(10), a(10) {}
// Delegating default constructor
Foo() : Foo(10) {}
private: Foo(int _a) : Base(_a), a(_a) {}
};
Alternatively, if the value of the constant doesn't need to be configurable, then you can make it a per-class constant (rather than per-object):
struct Foo : Base
{
static const int a = 10;
Foo() : Base(a) {}
};
const int Foo::a; // only if you ODR-use Foo::a

Virtual calls during construction / destruction

C++ Standard 12.7/4 says:
When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class's non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor's or destructor's class and not one overriding it in a more-derived class. If the virtual function call uses an explicit class member access (5.2.5) and the object expression refers to the complete object of x or one of that object's base class subobjects but not x or one of its base class subobjects, the behavior is undefined.
This text is the same in all versions I checked (though in C++03 it was paragraph 12.7/3).
My question is about the phrase "uses an explicit class member access". Possibly the point of that phrase is to point out that in the constructor/destructor body, virtual calls that use the implicit this-> are safe since the object expression does refer to the object x:
struct A;
A* p;
struct A {
A() { p = this; }
virtual ~A() { if (p == this) p = nullptr; }
virtual void f() {}
};
struct B {
B();
virtual ~B();
virtual void g() {}
};
struct C : public A, public B {
virtual void f() {}
virtual void g() {}
};
B::B() {
if (p) p->f(); // UB if `p` and `this` point at same complete object
g(); // Definitely safe, calls B::g().
}
B::~B() {
if (p) p->f(); // UB if `p` and `this` point at same complete object
g(); // Definitely safe, calls B::g().
}
int main() {
C c; // UB in B::B() and B::~B()!
}
But what if the virtual function call is not syntactically in the definition of the constructor or destructor, but is called indirectly? What is the behavior of this program?
#include <iostream>
struct A {
virtual void f() { std::cout << "A::f()\n"; }
void h() { f(); }
};
struct B {
explicit B(A& a) { a.h(); }
};
struct C : public A, public B {
C() : A(), B(static_cast<A&>(*this)) {}
virtual void f() { std::cout << "C::f()\n"; }
};
int main() {
C c;
}
I would expect that in B::B(A&), calling a.h() is just as undefined as calling a.f(). But we can't say the last sentence in 12.7/4 applies, since the virtual function call does not use an explicit class member access. Have I missed something? Are a.f() and a.h() really supposed to act differently in this context? Is there a Defect Report related to this? Should there be?
9.3.1/3 (in N3485) says
When an id-expression (5.1) that is not part of a class member access syntax (5.2.5) and not used to form
a pointer to member (5.3.1) is used in a member of class X in a context where this can be used (5.1.1),
if name lookup (3.4) resolves the name in the id-expression to a non-static non-type member of some class
C, and if either the id-expression is potentially evaluated or C is X or a base class of X, the id-expression is
transformed into a class member access expression (5.2.5) using (*this) (9.3.2) as the postfix-expression to
the left of the . operator.
In your second example, this means the body of A::h() gets transformed into (*this).f(), making the call an explicit class member access. Thus the last line of 12.7/4 applies; the behavior is undefined.
It should not make any difference.
The standard says:
When a virtual function is called directly or indirectly
However, your compiler may well have a bug - perhaps because it optimises the code in h, thinking that it understands what is going on (and not actually doing the right thing). You haven't mentioned WHICH compiler you are using, so it's not possible to say if there is a defect report...
Edit: Both g++ 4.8.2 and clang++ 3.5 prior to release from a few weeks back (with -std=c++11, in case that makes a difference) calls C::f() in the destructor, and A::f() in the constructor for your first testcase. In the second test-case, g++ calls A::f(), where clang++ calls C::f(). So clearly, the compiler seems to do "whatever it feels like" here. [Note that since it's "undefined", it can do all sorts of different things, including "what you expect"].
(In the first test-case, I modified p to be a to make it compile, and added printouts in f and g functions)

deleted default constructor headache

My c++ book says this (lippman, c++ primer, fifth ed., p. 508):
The synthesized default constructor is defined as deleted if the class ... has a const member whose type does not explicitly define a default constructor and that member does not have an in-class initializer. (emphesis mine)
Why then does this code produce an error?
class Foo {
Foo() { }
};
class Bar {
private:
const Foo foo;
};
int main() {
Bar f; //error: call to implicitly-deleted default constructor of 'Bar'
return 0;
}
The rule above seems to indicate that it should not be an error, because Foo does explicitly define a default constructor. Any ideas?
To fix your error. You need to make Foo::Foo() public.
class Foo
{
public:
Foo() { }
};
Otherwise I do believe it is private.
Is this what your looking for?
The default constructor is omitted when a a class construction isn't trivial.
That in general means that either there is an explicit constructor that receives parameters (and then you can't assume that it can be constructed without those parameters)
Or if one of the members or base classes need to be initiated in construction (They themselves don't have a trivial constructor)
I think that this should work
class Foo {
public:
Foo() { }
};
class Bar {
public:
Bar() : foo() {}
private:
const Foo foo;
};

Is it standard C++ to assign a member pointer to the address of another member in the constructor initializer?

Does this conform to the standard?
class Foo {
Bar m_bar;
Bar * m_woo;
public:
Foo() : m_bar(42, 123), m_woo(&m_bar) { }
};
It is correct. What is not correct is dereferencing that pointer before that particular subobject has been fully initialized.