Re: Using "this" in a base initializer list?
On May 8, 8:39 pm, "Victor Bazarov" <v.Abaza...@comAcast.net> wrote:
Alf P. Steinbach wrote:
* Victor Bazarov:
James Kanze wrote:
On May 8, 3:25 pm, "Victor Bazarov" <v.Abaza...@comAcast.net> wrote:
Angel Tsankov wrote:
Hello! Is the following code illformed or does it yield undefined
behaviour:
class a
{};
class b
{
public:
b(a&){}
};
class c: private a, private b
{
public:
c():b(*this){}
};
Neither. The code is fine.
Are you sure? Throw in some virtual inheritance, and it core
dumps with Sun CC. [..]
Huh? Throw in division by zero or dereferencing a null pointer
and it may release nasal demons. What's it got to do with the
code at hand?
James is referring to the conversion from c* to a*, which =A73.8/5 says
is Undefined Behavior.
Yes, but where did you find that conversion? There is reference
binding (8.5.3/5), but no pointer conversion.
So we end up in the following paragraph, which basically says
exactly the same thing about lvalues which refer to the object
(*this is an lvalue which refers to the complete C object):
Similarly, before the lifetime of an object has started
but after the storage which the object will occupy has
been allocated or, after the lifetime of an object has
ended and before the storage which the object occupied
is reused or released, any lvalue which refers to the
original object may be used but only in limited
ways.[...] if the original object will be or was of a
non-POD class type, the program has undefined behavior
if:
[...]
-- the lvalue is implicitly converted (4.10) to a
reference to a base class type,
The standard rather explicitly says that this is undefined
behavior. In practice, as Alf points out, it has to work in
some cases. But we don't really know which.
But the interpretation that yields that
conclusion also means that this,
struct S
{
void foo() {}
S() { this->foo(); }
};
It's things like this which make me think that there might be
some special rules for this. The standard does expliclty say
(=A79.3.1/1) that:
A non-static member function may be called for an object
of its class type, or for an object of a class derived
(clause 10) from its class type, using the class member
access syntax (5.2.5, 13.3.1.1). A non-static member
function may also be called directly using the function
call syntax (5.2.2, 13.3.1.1)
-- from within the body of a member function of its
class or of a class derived from its class, or
-- from a mem-initializer (12.6.2) for a constructor
for its class or for a class derived from its class.
Which taken literally, means that S::foo() or just foo() is
legal, but this->foo() isn't. (Which, of course, doesn't
really make sense.)
is undefined behavior, so that the common technique of using an
init-function called from multiple constructors, would be formally
Undefined Behavior. Which really means that part of the standard is
fishy Fishy FISHY, and should not be taken verbatim: some constructive
interpretation required, and I think it's impossible to say whether
the code above is formally OK (or not), only that it's in-practice OK.
<shrug> The reference (or pointer) is not being converted/used in the
code at all, why all the fuss?
Sorry. In the expression *this, this is a pointer to a c.
An the lvalue resulting from the expression is an lvalue
referring to the as yet not fully constructed c object. So
you have to consider such conversions. The conversion in
question is explicity defined by the standard as being
undefined behavior. In addition, as I pointed out, I have
seen the conversion, or at least similar conversions, fail
in real compilers. It bothers me, because the compiler does
have to be capable of doing the conversion, at least behind
the scenes. (But only on the this pointer, and only during
actual construction.)
--
James Kanze (Gabi Software) email: james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34