 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Matthias Hofmann Guest
|
Posted: Sat Dec 13, 2003 2:13 am Post subject: Using 'this' in member initializer list |
|
|
Hello,
I got a class which has another class as a member. The nested class needs to
store a reference to the containing class, so I want to initialize the
nested class as follows:
class Outer
{
Outer() : Inner( *this ) {} // Error C4355
class Inner
{
public:
Inner( Outer& r ) : m_rOuter( r ) {}
private:
Outer& m_rOuter;
};
};
When I compile the code on Visual C++ 6.0, I get a C4355 error. The
documentation in the MSDN Library describes the error as follows:
"Compiler Warning (levels 1 and 4) C4355
'this' : used in base member initializer list
The this pointer is only valid within nonstatic member functions, but was
used in the initializer list for a base class.
This is a level-1 warning when Microsoft extensions are enabled (/Ze) and a
level-4 warning otherwise."
My current workaround is to initialize the reference to the outer class in
the body of Outer::Outer(). However, this has proven to be error prone as I
often use this pattern in our current project. I have often forgotten to
initialize the reference, thus dereferencing a dangling pointer or reference
and taking quite a while to figure out what went wrong.
What does the standard say about this?
Best regards,
Matthias Hofmann
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ron Natalie Guest
|
Posted: Sat Dec 13, 2003 11:14 am Post subject: Re: Using 'this' in member initializer list |
|
|
"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote
| Quote: | Hello,
I got a class which has another class as a member. The nested class needs
to
store a reference to the containing class, so I want to initialize the
nested class as follows:
It's not an error, it's a wanring. It's letting you know that you have to |
be careful
that the other object doesn't do anything with "this" that expects it to be
fully
constructed (which it is not).
You can suppress the warning with a pragma.
| Quote: | My current workaround is to initialize the reference to the outer class in
the body of Outer::Outer().
|
I have no idea what you mean by that. You can not "initialize" a the member
reference
like that. If you leave the reference uninitialized the program is
ill-formed.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jonathan Turkanis Guest
|
Posted: Sat Dec 13, 2003 11:19 am Post subject: Re: Using 'this' in member initializer list |
|
|
"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote in message:>
| Quote: | I got a class which has another class as a member. The nested class needs
to
store a reference to the containing class, so I want to initialize the
nested class as follows:
class Outer
{
Outer() : Inner( *this ) {} // Error C4355
class Inner
{
public:
Inner( Outer& r ) : m_rOuter( r ) {}
private:
Outer& m_rOuter;
};
};
|
I assume you mean something like this:
class Outer {
Outer() : inner( *this ) { }
class Inner {
public:
Inner( Outer& r ) : m_rOuter( r ) {}
private:
Outer& m_rOuter;
};
Inner inner;
};
Secction 9.3.2 of the standard [class.this] says "In the body of a nonstatic
(9.3) member function, the keyword this is a non-lvalue expression whose
value is the address of the object for which the function is called."
Section 12.1 [class.ctor] says that constructors are non-static member
functions, and 8.4 [dcl.fct.def] together with 12.6.2 [class.base.init] make
it clear that member initializer lists are outside the function body. It
would seem to follow that the 'this' pointer is not allowed in member
initializer lists. I'm not sure why the Microsoft compilers consider this an
error while many other compilers let it pass.
| Quote: | My current workaround is to initialize the reference to the outer class in
the body of Outer::Outer(). However, this has proven to be error prone as
I
often use this pattern in our current project. I have often forgotten to
initialize the reference, thus dereferencing a dangling pointer or
reference
and taking quite a while to figure out what went wrong.
|
There is an idiom you can use which will ensure that the pointer to the
outer object is automatically initialized. However, I'm not sure remembering
to use the idiom will be any easier than remembering to initialize the
pointer to the outer object. There are some weaknesses in the following
formulation; perhaps you can spiff it up.
Library templates:
template<typename Outer>
struct inner{
typedef Outer outer_type;
Outer* outer;
};
template<typename Inner>
class outer {
protected:
outer() {
typedef typename Inner::outer_type outer_type;
inner.outer = static_cast<outer_type*>(this);
}
Inner inner;
};
Now derive the inner class from a specialization of inner, and the outer
class from a specialization of outer, and the inner pointer to the outer
object will be set automatically:
template<typename Outer>
class MyInnerClass : public inner<Outer> {
// Use inherited member 'outer' anywhere but in ctor or dtor.
};
struct MyClass : public outer< MyInnerClass {
// Inherited member 'inner' has pointer to this object set
automatically
};
Jonathan
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Siemel Naran Guest
|
Posted: Sun Dec 14, 2003 1:58 am Post subject: Re: Using 'this' in member initializer list |
|
|
"Ron Natalie" <ron (AT) sensor (DOT) com> wrote
| Quote: | "Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote in message
It's not an error, it's a wanring. It's letting you know that you have
to
be careful
that the other object doesn't do anything with "this" that expects it to
be
fully
constructed (which it is not).
|
You can set up your compiler options to flag any warning as an error, which
could be the case for the OP.
| Quote: | You can suppress the warning with a pragma.
|
If I remember correctly it is #pragma (enable: 4355) and #pragma (default:
4355) or something like that. But check the MSVC docs and newsgroups.
--
+++++++++++
Siemel Naran
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jonathan Turkanis Guest
|
Posted: Sun Dec 14, 2003 2:00 am Post subject: Re: Using 'this' in member initializer list |
|
|
"Jonathan Turkanis" <technews (AT) kangaroologic (DOT) com> wrote in message:
| Quote: | Secction 9.3.2 of the standard [class.this] says "In the body of a
nonstatic
(9.3) member function, the keyword this is a non-lvalue expression whose
value is the address of the object for which the function is called."
Section 12.1 [class.ctor] says that constructors are non-static member
functions, and 8.4 [dcl.fct.def] together with 12.6.2 [class.base.init]
make
it clear that member initializer lists are outside the function body. It
would seem to follow that the 'this' pointer is not allowed in member
initializer lists. I'm not sure why the Microsoft compilers consider this
an
error while many other compilers let it pass.
|
Aha! I found the answer (12.6.2 paragraph 7):
[Note: because the meminitializer 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. ]
I've wondered about this before, and seemed to have missed this note.
"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote in message :
| Quote: | My current workaround is to initialize the reference to the outer class in
the body of Outer::Outer(). However, this has proven to be error prone as
I
often use this pattern in our current project. I have often forgotten to
initialize the reference, thus dereferencing a dangling pointer or
reference
and taking quite a while to figure out what went wrong.
|
Using a reference to the outer object will force you to initialize it in the
member initializer list.
Jonathan
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Matthias Hofmann Guest
|
Posted: Sun Dec 14, 2003 8:53 pm Post subject: Re: Using 'this' in member initializer list |
|
|
Siemel Naran <SiemelNaran (AT) REMOVE (DOT) att.net> schrieb in im Newsbeitrag:
D%JCb.190792$Ec1.7056906 (AT) bgtnsc05-news (DOT) ops.worldnet.att.net...
| Quote: | "Ron Natalie" <ron (AT) sensor (DOT) com> wrote
"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote in message
It's not an error, it's a wanring. It's letting you know that you have
to
be careful
that the other object doesn't do anything with "this" that expects it to
be
fully
constructed (which it is not).
You can set up your compiler options to flag any warning as an error,
which
could be the case for the OP.
|
[snip]
It was in fact a warning, but being a conscientious programmer, a warning is
an error to me... ;-)
Best regards,
Matthias
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Matthias Hofmann Guest
|
Posted: Sun Dec 14, 2003 8:56 pm Post subject: Re: Using 'this' in member initializer list |
|
|
Ron Natalie <ron (AT) sensor (DOT) com> schrieb in im Newsbeitrag:
3fda7d2d$0$221$9a6e19ea (AT) news (DOT) newshosting.com...
| Quote: |
"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote in message
news:brcrqf$2ag$1 (AT) news1 (DOT) nefonline.de...
Hello,
I got a class which has another class as a member. The nested class
needs
to
store a reference to the containing class, so I want to initialize the
nested class as follows:
It's not an error, it's a wanring. It's letting you know that you have
to
be careful
that the other object doesn't do anything with "this" that expects it to
be
fully
constructed (which it is not).
|
Then I wonder why I don't get the same warning when I use a pointer instead
of a reference and assign 'this' to the pointer in the body of the
constructor:
class Outer
{
Outer()
{
m_inner.m_pOuter = this; // No error, though it is basically the
same.
}
class Inner
{
public:
Outer* m_pOuter;
} m_inner;
};
Besides, MS VC++ 6.0 talks about "Microsoft Extensions" that can be used to
make the code work.
| Quote: |
You can suppress the warning with a pragma.
My current workaround is to initialize the reference to the outer class
in
the body of Outer::Outer().
I have no idea what you mean by that. You can not "initialize" a the
member
reference
like that. If you leave the reference uninitialized the program is
ill-formed.
|
I should have said that in that case, I use a pointer instead of a
reference. I assign 'this' to the pointer of type Outer* in the body of the
constructor, see above.
Best regards,
Matthias
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Matthias Hofmann Guest
|
Posted: Sun Dec 14, 2003 8:57 pm Post subject: Re: Using 'this' in member initializer list |
|
|
Jonathan Turkanis <technews (AT) kangaroologic (DOT) com> schrieb in im Newsbeitrag:
brfm1v$2oolf$1 (AT) ID-216073 (DOT) news.uni-berlin.de...
| Quote: |
"Jonathan Turkanis" <technews (AT) kangaroologic (DOT) com> wrote in message:
Secction 9.3.2 of the standard [class.this] says "In the body of a
nonstatic
(9.3) member function, the keyword this is a non-lvalue expression whose
value is the address of the object for which the function is called."
Section 12.1 [class.ctor] says that constructors are non-static member
functions, and 8.4 [dcl.fct.def] together with 12.6.2 [class.base.init]
make
it clear that member initializer lists are outside the function body. It
would seem to follow that the 'this' pointer is not allowed in member
initializer lists. I'm not sure why the Microsoft compilers consider
this
an
error while many other compilers let it pass.
Aha! I found the answer (12.6.2 paragraph 7):
[Note: because the meminitializer 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. ]
I've wondered about this before, and seemed to have missed this note.
|
This is good news! So I can initialize Inner with the 'this' pointer of
outer - I was really close to proposing a change to the standard... ;-)
By the way, does any one know wether VC++ 7.0 also complains about this?
| Quote: |
"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote in message :
My current workaround is to initialize the reference to the outer class
in
the body of Outer::Outer(). However, this has proven to be error prone
as
I
often use this pattern in our current project. I have often forgotten to
initialize the reference, thus dereferencing a dangling pointer or
reference
and taking quite a while to figure out what went wrong.
Using a reference to the outer object will force you to initialize it in
the
member initializer list.
|
As stated in another post, I use a pointer in that case.
Best regards,
Matthias Hofmann
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Balog Pal Guest
|
Posted: Mon Dec 15, 2003 10:20 am Post subject: Re: Using 'this' in member initializer list |
|
|
"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote
| Quote: | It was in fact a warning, but being a conscientious programmer, a warning
is
an error to me...
|
A programmer shall not ignore warnings, but he doesn't have to treat them as
errors either. This warning is a good one for the 'general' case. You
pass 'this' out from the init list. At that point your object is far from
being complete. The function you pass it into may or may not expect a usable
instance of *this. Id it does you are in trouble. As touching any not yet
constructed parts is UB to start with. If you replace call to ctor body it
is no longer UB, but as your ctor is not complete, some class inariants may
yet be off, or you may have issegal "logical" state.
For such use of this the called function shall do nothing but store the
pointer. For some later use that will happen after that ctor actually
finished its work. If you do that, you can ignore the warning, and disable
it for that one shot (starting V6, warning setup has push/pop, so that's an
easy push-disable-pop sequence.)
Paul
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Daniel Krügler (nee Spang Guest
|
Posted: Mon Dec 15, 2003 10:29 am Post subject: Re: Using 'this' in member initializer list |
|
|
Good Morning, Matthias!
Matthias Hofmann schrieb:
| Quote: | It was in fact a warning, but being a conscientious programmer, a warning is
an error to me...
|
This is a good rule in general, but every rule has its exceptions. One basic
problem is,
that a compiler is allowed to diagnose **anything** as a warning, and sometimes
it
is hard to decide unambigiously, whether a warning is acceptable or not.
In the mentioned case a critical situation can arise for example in the
following
situations:
The reference to this or *this...
- ..is used to call a member function, which accesses a member, which is not yet
initialized.
- ..is used to call a virtual member function and the programmer assumes usual
polymorphic behaviour.
but there also exist many (May I see most?) situations, where the access to a
this
reference is absolutely harmless and legal. So, my solution for this situation
is:
Analyse the corresponding code part carefully and if it is harmless, deactivate
locally the warning (OK, the other case explains by itself, doesn't it ).
Yes, this solution is not fool-proof. Think of others, who modify your codings
hoping,
that "the compiler will warn you, if necessary". But to my opinion this is a bad
programming style anyway, because then the programmer tends to left his/her
responsibility to the compiler and does not use his/her own brain - which is
usually a
bad idea.... (As I said: No rule w/o exceptions......)
Just my 0.02 EURO cent,
Daniel
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Richter Guest
|
Posted: Mon Dec 15, 2003 4:04 pm Post subject: Re: Using 'this' in member initializer list |
|
|
Hi,
| Quote: | Then I wonder why I don't get the same warning when I use a pointer instead
of a reference and assign 'this' to the pointer in the body of the
constructor:
class Outer
{
Outer()
{
m_inner.m_pOuter = this; // No error, though it is basically the
same.
}
|
Basically a design decision the guys at Microsoft made. There is no
obvious test here whether "this" object is fully constructed at the point
you make use of the "this" pointer, so no warning is generated. Consider
a situation where "this" gets used in an assigment as the last line of
the constructor. This might be considered fine because "this" object is
fully constructed then. (Though possibly not a derived object that called
the constructor as base constructor of its own constructor.)
Similar to the above, using "this" in the constructor might, but need
not to indicate a problem.
I don't think there's much of a logical argument why one warns and the
other doesn't, both are potentially dangerous, though the first case
might be easier to detect.
| Quote: | Besides, MS VC++ 6.0 talks about "Microsoft Extensions" that can be used to
make the code work.
|
If you *just* store the pointer to make use of it later there is no
reason why you would need any extensions to make the program work, it will
do right away. Just make sure that you remember that you're passing a pointer
to an incomplete object (incomplete as in "not yet fully constructed").
What I find even more irritating about this warning is that it also warns
in cases where only a pointer to the base class is required, which, at the
indicated position, is already fully initialized:
class Base {
...
public:
Base()
{ }
}
class Holder {
class Base *base;
public:
Holder(class Base *b)
: base(b)
{ }
};
class Derived : public Base {
class Holder h;
//
public:
Derived()
: h(this) // <-- warning here.
{ }
};
This warning seems now really completely bogus to me as Holder requires only a
base object, which is fully constructed at the indicated position.
In other words: Put a *BIG* warning sign into the code at this position,
and disable the warning. It is often more confusing than helping...
So long,
Thomas
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Richter Guest
|
Posted: Mon Dec 15, 2003 4:05 pm Post subject: Re: Using 'this' in member initializer list |
|
|
Hi,
| Quote: | This is good news! So I can initialize Inner with the 'this' pointer of
outer - I was really close to proposing a change to the standard... ;-)
By the way, does any one know wether VC++ 7.0 also complains about this?
|
I don't know about 7.0, but VC++ 7.1 also warns about this. And yes, I
also disabled it here. (With all the precautions and a comment in my
code.)
So long,
Thomas
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Siemel Naran Guest
|
Posted: Mon Dec 15, 2003 5:25 pm Post subject: Re: Using 'this' in member initializer list |
|
|
"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote
| Quote: | It was in fact a warning, but being a conscientious programmer, a warning
is
an error to me...
|
This is good practice. Many times I've ignored warnings, or seen people
ignore warnings, in order that the program pass compilation quickly. But
the resulting program will behave erroneously, either crashing or giving the
wrong result -- and since the bug is subtle it is very hard to nail down.
--
+++++++++++
Siemel Naran
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Andrea Griffini Guest
|
Posted: Mon Dec 15, 2003 5:27 pm Post subject: Re: Using 'this' in member initializer list |
|
|
On 14 Dec 2003 15:53:09 -0500, "Matthias Hofmann"
<hofmann (AT) anvil-soft (DOT) com> wrote:
| Quote: | It was in fact a warning, but being a conscientious programmer, a warning is
an error to me...
|
There's no way to compile standard code with VC++ 6 without
ignoring some warning (4786, for example) and without playing
ugly tricks like "#define for if(0);else for".
Andrea
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Risto Lankinen Guest
|
Posted: Tue Dec 16, 2003 11:23 am Post subject: Re: Using 'this' in member initializer list |
|
|
Hi!
"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote
| Quote: |
"Compiler Warning (levels 1 and 4) C4355
'this' : used in base member initializer list
The this pointer is only valid within nonstatic member functions, but was
used in the initializer list for a base class.
|
One other reason for not passing the "this" pointer outside
from a constructor, is that the constructor does not know if
you are constructing a const instance or not. Consider this:
class C;
C *p; // Pointer to non-const 'C'
class C
{
friend int main();
int i;
C() : i(0) { p = this; } // Leaks a non-const pointer...
void f() { i = 101; }
void f() const {}
};
int main()
{
C const c; // ... to a const instance!
cout << c.i;
p->f();
cout << c.i; // Const object has been changed!!!!!
}
All this is legal C++, and I haven't been able to find anything in
the standard that would deem this to be undefined behaviour.
The comment about manipulating an object that was created as
a result of a const_cast comes closest, BUT note that there is
no cast of any kind anywhere in the above code.
Cheers!
- Risto -
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|