By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,106 Members | 1,079 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,106 IT Pros & Developers. It's quick & easy.

Using "this" in a base initializer list?

P: n/a
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){}

};

May 8 '07 #1
Share this Question
Share on Google+
10 Replies


P: n/a
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.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
May 8 '07 #2

P: n/a
On May 8, 9:21 am, "Angel Tsankov" <fn42...@fmi.uni-sofia.bgwrote:
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){}
Ambiguous call. b(const b&) and b(a&)
>

};- Hide quoted text -

- Show quoted text -

May 8 '07 #3

P: n/a
siddhu wrote:
On May 8, 9:21 am, "Angel Tsankov" <fn42...@fmi.uni-sofia.bgwrote:
>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){}

Ambiguous call. b(const b&) and b(a&)
You're right! How did I miss that? <redface>
>

>>

};- Hide quoted text -

- Show quoted text -
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
May 8 '07 #4

P: n/a
On May 8, 3:25 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
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. And §3.8 of the standard explicitly says
that:

Before the lifetime of an object has started but after
the storage which the object will occupy has been
allocated39) or, after the lifetime of an object has
ended and before the storage which the object occupied
is reused or released, any pointer that refers to the
storage location where the object will be or was located
may be used but only in limited ways.[...] If the
object will be or was of a non-POD class type, the
program has undefined behavior if
[...]
-- the pointer is implicitly converted (4.10) to a
pointer to a base class type,

(Quoted from the April, 2006 draft. The only one I have
handy here. But I don't think the text in question has
changed since the original standard.)

I think that there are some special rules concerning the
this pointer, but I can't find them off hand. If you can
find them, and point them out to me, I'd be very happy.
I really want this to be defined.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

May 8 '07 #5

P: n/a


--
Angel Tsankov
fn*****@fmi.uni-sofia.bg
"siddhu" <si***********@gmail.comwrote in message
news:11**********************@p77g2000hsh.googlegr oups.com...
On May 8, 9:21 am, "Angel Tsankov" <fn42...@fmi.uni-sofia.bg>
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){}

Ambiguous call. b(const b&) and b(a&)
>>

};- Hide quoted text -
Well, I meant this:

class c: private a, private b
{
public:
c():b(static_cast<a&>(*this)){}
};

May 8 '07 #6

P: n/a
James Kanze wrote:
On May 8, 3:25 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>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?
May 8 '07 #7

P: n/a
* Victor Bazarov:
James Kanze wrote:
>On May 8, 3:25 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>>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 §3.8/5 says is
Undefined Behavior. But the interpretation that yields that conclusion
also means that this,

struct S
{
void foo() {}
S() { this->foo(); }
};

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.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
May 8 '07 #8

P: n/a
Alf P. Steinbach wrote:
* Victor Bazarov:
>James Kanze wrote:
>>On May 8, 3:25 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
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 §3.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.
But the interpretation that yields that
conclusion also means that this,

struct S
{
void foo() {}
S() { this->foo(); }
};

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?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
May 8 '07 #9

P: n/a
On May 8, 8:16 pm, "Alf P. Steinbach" <a...@start.nowrote:
* Victor Bazarov:
James Kanze wrote:
On May 8, 3:25 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
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 §3.8/5 says is
Undefined Behavior. But the interpretation that yields that conclusion
also means that this,
struct S
{
void foo() {}
S() { this->foo(); }
};
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,
You get that feeling too. Realistically, at least some of the
uses must be defined, regardless of what the standard says. But
which ones?
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.
In this simple case. That's why I mentionned that I'd actually
had a problem with a real compiler in the past. It's because I
had the problem that I'd familiarized myself with the standard,
too. I wanted to complain about a compiler error, but the
standard didn't support me.

Logically, I still have trouble understanding *why* it should be
undefined behavior. The compiler must be able to do the
conversion, since it has to get the correct address for the this
pointer it passes to the base class constructors. In my case,
the code was very clear:

class MyStream
: public virtual MyStreambuf
, public std::ostream
{
} ;

The organization was such in order to ensure that the streambuf
was constructed before its address was passed to std::ostream.
Initializing std::ostream with this, however, resulted in the
wrong address being passed, and a core dump later, when ostream
used it. Removing the virtual worked. What also worked was
wrapping the streambuf:

template< typename Streambuf >
class StreambufWrapper
{
public:
std::streambuf* getStreambuf() { return &myStreambuf ; }
Streambuf myStreambuf ;
} ;

class MyStream
: public virtual StreambufWrapper< MyStreambuf >
: public std::ostream
{
public:
MyStream() : std::ostream( getStreambuf() ) {}
} ;

Obviously, the compiler had to do successfully convert this to a
pointer to the base class in order to call getStreambuf(), but
for who knows what reason, it was unable to do it correctly when
this was passed to the constructor.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

May 8 '07 #10

P: n/a
On May 8, 8:39 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
Alf P. Steinbach wrote:
* Victor Bazarov:
James Kanze wrote:
On May 8, 3:25 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
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 §3.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
(§9.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: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

May 8 '07 #11

This discussion thread is closed

Replies have been disabled for this discussion.