| Home | Forums | Reviews | Guides | Newsgroups | Register | Search |
![]() |
| Thread Tools |
| huili80@gmail.com |
|
|
|
| |
|
Neelesh
Guest
Posts: n/a
|
On May 6, 5:36*am, huil...@gmail.com wrote:
> Is the following code valid? > > template < typename F > > struct base1 > { > * * * * base1(const F& f):f(f){} > * * * * const F& f; > > }; > > template < typename E1, typename E2 > > struct base2 > { > * * * * base2(const E1& e1, const E2& e2):e1(e1),e2(e2){} > * * * * const E1& e1; > * * * * const E2& e2; > > }; > > template < typename F1, typename F2 > > struct derived : base1<F1> > * * * * * * * * * * * * * * * * ,base2<base1<F1>,F2> > { > * * * * derived(const F1& f1, const F2& f2) > * * * * * * * * :base1<F1>(f1) > * * * * * * * * ,base2<base1<F1>,F2>(static_cast<base1<F1> const&>(*this), f2) // is > this okay? > * * * * {} > > > > }; Yes, the code is valid and the static_cast is not needed. 12.6.2p7 ....because the meminitializer are evaluated in the scope of the constructor, the this pointer can be used in the expressionlist of a meminitializer to refer to the object being initialized. |
|
|
|
|
|||
|
|||
| Neelesh |
|
|
|
| |
|
James Kanze
Guest
Posts: n/a
|
On May 6, 6:22 am, Neelesh <neelesh.bo...@gmail.com> wrote:
> On May 6, 5:36 am, huil...@gmail.com wrote: > > Is the following code valid? > > template < typename F > > > struct base1 > > { > > base1(const F& f):f(f){} > > const F& f; > > }; > > template < typename E1, typename E2 > > > struct base2 > > { > > base2(const E1& e1, const E2& e2):e1(e1),e2(e2){} > > const E1& e1; > > const E2& e2; > > }; > > template < typename F1, typename F2 > > > struct derived : base1<F1> > > ,base2<base1<F1>,F2> > > { > > derived(const F1& f1, const F2& f2) > > :base1<F1>(f1) > > ,base2<base1<F1>,F2>(static_cast<base1<F1> const&>(*this), f2) // is > > this okay? > > {} > > }; > Yes, the code is valid and the static_cast is not needed. > 12.6.2p7 > ...because the meminitializer are evaluated in the scope of the > constructor, the this pointer can be used in the expressionlist of a > meminitializer to refer to the object being initialized. No, it's not valid. The expression *this is an lvalue expression with type derived. Type derived has a non-trivial constructor. According to §3.8: [...] The lifetime of an object of type T begins when: -- storage with the proper alignment and size for type T is obtained, and -- if T is a class type with a non-trivial constructor (12.1), the constructor call has completed. Furthermore: 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 pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. Such a pointer refers to allocated storage (3.7.3.2), and using the pointer as if the pointer were of type void*, is well-defined. Such a pointer may be dereferenced but the resulting lvalue may only be used in limited ways, as described below. If the object will be or was of a class type with a non-trivial destructor, and the pointer is used as the operand of a delete-expression, the program has undefined behavior. If the object will be or was of a non-POD class type, the program has undefined behavior if: [...] -- the pointer is used to access a non-static data member or call a non-static member function of the object, or -- the pointer is implicitly converted (4.10) to a pointer to a base class type, or -- the pointer is used as the operand of a static_cast (5.2.9) (except when the conversion is to void*, or to void* and subsequently to char*, or unsigned char*). There's no exception that I can see for the this pointer. Practically, I'm not sure what this means. You definitely can call non-static member functions of already constructed sub-objects, and you obviously call the constructor of the sub-objects, so the compiler must be able to convert the this pointer at this point. On the other hand, I've had such conversions actually fail (admittedly only when the base class in question was a virtual base); in my case, adding a member function in the base class which did nothing but return this, and calling it, solved the problem. (Similarly, I've never heard of it failing in the body of the constructor, although according to the above text, it's still undefined behavior.) -- James Kanze (GABI Software) email: 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 |
|
|
|
|
|||
|
|||
| James Kanze |
|
Neelesh
Guest
Posts: n/a
|
On May 6, 1:51*pm, James Kanze <james.ka...@gmail.com> wrote:
> On May 6, 6:22 am, Neelesh <neelesh.bo...@gmail.com> wrote: > > > > > > > On May 6, 5:36 am, huil...@gmail.com wrote: > > > Is the following code valid? > > > template < typename F > > > > struct base1 > > > { > > > * * * * base1(const F& f):f(f){} > > > * * * * const F& f; > > > }; > > > template < typename E1, typename E2 > > > > struct base2 > > > { > > > * * * * base2(const E1& e1, const E2& e2):e1(e1),e2(e2){} > > > * * * * const E1& e1; > > > * * * * const E2& e2; > > > }; > > > template < typename F1, typename F2 > > > > struct derived : base1<F1> > > > * * * * * * * * * * * * * * * * ,base2<base1<F1>,F2> > > > { > > > * * * * derived(const F1& f1, const F2& f2) > > > * * * * * * * * :base1<F1>(f1) > > > * * * * * * * * ,base2<base1<F1>,F2>(static_cast<base1<F1> const&>(*this), f2) // is > > > this okay? > > > * * * * {} > > > }; > > Yes, the code is valid and the static_cast is not needed. > > 12.6.2p7 > > ...because the meminitializer are evaluated in the scope of the > > constructor, the this pointer can be used in the expressionlist of a > > meminitializer to refer to the object being initialized. > > No, it's not valid. *The expression *this is an lvalue > expression with type derived. *Type derived has a non-trivial > constructor. *According to §3.8: > > * * [...] The lifetime of an object of type T begins when: > > * * *-- storage with the proper alignment and size for type > * * * * T is obtained, and > > * * *-- if T is a class type with a non-trivial constructor > * * * * (12.1), the constructor call has completed. > > Furthermore: > > * * 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 pointer that refers to the > * * storage location where the object will be or was located > * * may be used but only in limited ways. *Such a pointer > * * refers to allocated storage (3.7.3.2), and using the > * * pointer as if the pointer were of type void*, is > * * well-defined. Such a pointer may be dereferenced but the > * * resulting lvalue may only be used in limited ways, as > * * described below. If the object will be or was of a class > * * type with a non-trivial destructor, and the pointer is > * * used as the operand of a delete-expression, the program > * * has undefined behavior. If the object will be or was of > * * a non-POD class type, the program has undefined behavior > * * if: > > * * [...] > > * * *-- the pointer is used to access a non-static data > * * * * member or call a non-static member function of the > * * * * object, or > > * * *-- the pointer is implicitly converted (4.10) to a > * * * * pointer to a base class type, or > > * * *-- the pointer is used as the operand of a static_cast > * * * * (5.2.9) (except when the conversion is to void*, or > * * * * to void* and subsequently to char*, or unsigned > * * * * char*). > > There's no exception that I can see for the this pointer. > hmm...yes..agreed. In fact, in the current case, 3.8p6 applies more appropriately: if the original object will be or was of a nonPOD class type, the program has undefined behavior if: [...] — the lvalue is implicitly converted (4.10) to a reference to a base class type, or [...] The lvalue (*this) has been converted to reference to base class type (base<F1>&) in the constructor of derived class, which would result in undefined behavior. However, I believe that this is somewhat strange and I donot see any obvious reason of not allowing this. > Practically, I'm not sure what this means. *You definitely > can call non-static member functions of already constructed > sub-objects, calling virtual functions of already constructed sub-objects could be a problem in a sense that it might behave differently for *this and for any other object of the same type. In the current case, if we use (*this) to initialize a reference e1 in constructor of base2, and call a virtual member function of e1 from constructor of class base2, I would not be surprized if the call is resolved by the base1 version, since there is no derived object constructed yet. template < typename F > struct base1 { base1(const F& f): f(f) { } const F& f; virtual void fun() const { cout << "base fun" << endl; } }; template < typename E1, typename E2 > struct base2 { base2(const E1& e1, const E2& e2): e1(e1), e2(e2) { e1.fun(); //calling member functions of member objects is fine in general, but creates problems when e1 is a reference to the derived object being constructed } const E1& e1; const E2& e2; }; template < typename F1, typename F2 > struct derived : base1<F1>, base2<base1<F1>,F2> { derived(const F1& f1, const F2& f2): base1<F1>(f1), base2<base1<F1>,F2>(*this, f2) //Assume this was legal somehow {} virtual void fun() const { cout << "derived fun" << endl; } }; The call e1.fun(); would typically get resolved dynamically. However, in the current case, since we are passing a reference to an not-yet- completely constructed-object, the call would get resolved by calling the base1::fun() instead of derived::fun(). (Of course provided that passing *this in the constructor of derived class was somehow legal.) Another example to illustrate this point: class X { public: X() { } X(const X& x1, const X& x2) { x1.f(); x2.f(); //check if call to f() is resolved dynamically or not } virtual void f() const { std::cout << "base" << std::endl; } }; class Z { public: Z() { } Z(int m, const X& x) : X(x, *this) //pass two objects of same type, one completely constructed and one partially constructed. Assume that passing *this was valid somehow. { } virtual void f() const { std::cout << "derived" << std::endl; } }; int main() { Z z; Z z2(1, z); //Dummy parameter 1 added, otherwise it will call the CC. } Prints "base" and the "derived", indicating that x.f() is resolved dynamically but not x2.f(). However, I doubt if this is "strong" enough reason to disallow passing (*this) to base class constructor. Thanks. >[...] |
|
|
|
|
|||
|
|||
| Neelesh |
|
James Kanze
Guest
Posts: n/a
|
On May 6, 1:07 pm, Neelesh <neelesh.bo...@gmail.com> wrote:
> On May 6, 1:51 pm, James Kanze <james.ka...@gmail.com> wrote: > > On May 6, 6:22 am, Neelesh <neelesh.bo...@gmail.com> wrote: > > > On May 6, 5:36 am, huil...@gmail.com wrote: > > > > Is the following code valid? > > > > template < typename F > > > > > struct base1 > > > > { > > > > base1(const F& f):f(f){} > > > > const F& f; > > > > }; > > > > template < typename E1, typename E2 > > > > > struct base2 > > > > { > > > > base2(const E1& e1, const E2& e2):e1(e1),e2(e2){} > > > > const E1& e1; > > > > const E2& e2; > > > > }; > > > > template < typename F1, typename F2 > > > > > struct derived : base1<F1> > > > > ,base2<base1<F1>,F2> > > > > { > > > > derived(const F1& f1, const F2& f2) > > > > :base1<F1>(f1) > > > > ,base2<base1<F1>,F2>(static_cast<base1<F1> const&>(*this), f2) // is > > > > this okay? > > > > {} > > > > }; > > > Yes, the code is valid and the static_cast is not needed. > > > 12.6.2p7 > > > ...because the meminitializer are evaluated in the scope > > > of the constructor, the this pointer can be used in the > > > expressionlist of a meminitializer to refer to the object > > > being initialized. > > No, it's not valid. The expression *this is an lvalue > > expression with type derived. Type derived has a > > non-trivial constructor. According to §3.8: > > [...] The lifetime of an object of type T begins when: > > -- storage with the proper alignment and size for type > > T is obtained, and > > -- if T is a class type with a non-trivial constructor > > (12.1), the constructor call has completed. > > Furthermore: > > 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 pointer that refers to the > > storage location where the object will be or was located > > may be used but only in limited ways. Such a pointer > > refers to allocated storage (3.7.3.2), and using the > > pointer as if the pointer were of type void*, is > > well-defined. Such a pointer may be dereferenced but the > > resulting lvalue may only be used in limited ways, as > > described below. If the object will be or was of a class > > type with a non-trivial destructor, and the pointer is > > used as the operand of a delete-expression, the program > > has undefined behavior. If the object will be or was of > > a non-POD class type, the program has undefined behavior > > if: > > [...] > > -- the pointer is used to access a non-static data > > member or call a non-static member function of the > > object, or > > -- the pointer is implicitly converted (4.10) to a > > pointer to a base class type, or > > -- the pointer is used as the operand of a static_cast > > (5.2.9) (except when the conversion is to void*, or > > to void* and subsequently to char*, or unsigned > > char*). > > There's no exception that I can see for the this pointer. > hmm...yes..agreed. In fact, in the current case, 3.8p6 applies > more appropriately: > if the original object will be or was of a nonPOD class type, the > program has undefined behavior if: > [...] > — the lvalue is implicitly converted (4.10) to a reference to a base > class type, or > [...] > The lvalue (*this) has been converted to reference to base > class type (base<F1>&) in the constructor of derived class, > which would result in undefined behavior. > However, I believe that this is somewhat strange and I donot > see any obvious reason of not allowing this. I can't either. I think the case the standard is trying to address is that of some external pointer. Something along the lines of: Derived* p = static_cast< Derived* >( : new ( p ) Derived ; and then the base class constructor calls a function which tries to convert p to a Base*. There are very good reasons why this should be undefined behavior. And those reasons really apply to just about any pointer except this; the compiler can only do the conversion correctly if it knows (more or less) how much has or has not been constructed (at least if the base is virtual). In the case of this, however, the compiler knows exactly what the situation is, what parts have been constructed, and what parts haven't. And the compiler has to be able to do the conversion in order to call the various constructors of the base classes anyway, or to call member functions in already constructed base classes (which is allowed). > > Practically, I'm not sure what this means. You definitely > > can call non-static member functions of already constructed > > sub-objects, > calling virtual functions of already constructed sub-objects > could be a problem in a sense that it might behave differently > for *this and for any other object of the same type. Agreed. I'm not sure what calling a virtual function in such cases would mean. I.e. given: Derived: When "virtualFuncInBase1" is called, what is the dynamic type of the object? It can't yet be Derived, since we've yet to enter the body of Derived, and in the constructor of Base2, it will be Base2. And if it is Base2, there's likely no virtualFuncInBase1 in Base2, so the code shouldn't even compile. Maybe such calls are illegal. (My Unix machine is in the process of being upgraded, and all my copies of the standard are on it, so I can't verify anything for the moment.) What I can say is that I've actually had a case a bit like the above, where Base1 was virtual, and Base2 took a pointer to a base class of Base1. If I passed this, the generated code core dumped; if I called a member function of Base1 which returned this, the code worked. But of course, the behavior of one compiler doesn't prove anything (especially as other compilers got it right when I simply passed this). I'll look into it further once I get access to the standard again. The case does occur in one very common idiom: when creating an istream or ostream to use a custom streambuf. The classic idiom is: class myistream : private mystreambuf, public std::istream { public: myistream() : mystreambuf(), std::istream( this ) {} } ; , with variations on whether you explicitly cast the this or not, whether the inhertance of mystreambuf is virtual or not, etc. In the end, what I currently have is a wrapper class (templated) which contains the mystreambuf, and has a function which returns a pointer to it. The initializer expression for std::istream calls this function. > In the current case, if we use (*this) to initialize a > reference e1 in constructor of base2, and call a virtual > member function of e1 from constructor of class base2, I would > not be surprized if the call is resolved by the base1 version, > since there is no derived object constructed yet. That would be correct (supposing that Base2 takes a reference to a Base1). I don't see any problem there, provided the correct pointer (to the Base1 subobject) is passed to the constructor of Base2. The problem is getting the correct pointer. Consider: Derived* current ; Derived* factory() { current = static_cast< Derived* >( : new ( current ) Derived ; return current ; } Derived: : Base1() , Base2( *current ) // expects a Base1& { } If Base1 is virtual, do you really expect a compiler to be able to generate the correct code for the call to Base2 (supposing that it doesn't know analyse enought to know that current is always equal to this at this point---and I doubt many compilers are capable of that analysis). It can only suppose that current points to a fully constructed object, with a vptr which corresponds to that of the full object. Which isn't necessarily the case. The difference when you pass the this pointer, of course, is that the compiler does know the exact state of the pointed to object. And it does know how to find the address of any given base class. (It has to, since it has to be able to set up the this pointer when calling member functions of Base1 from the body of the constructor.) > template < typename F > struct base1 Just a nit, but none of this has anything to do with templates. Using templates in the examples just adds extra noise for the reader. > { > base1(const F& f): f(f) { } > const F& f; > virtual void fun() const { cout << "base fun" << endl; } > }; > template < typename E1, typename E2 > struct base2 > { > base2(const E1& e1, const E2& e2): > e1(e1), > e2(e2) > { > e1.fun(); //calling member functions of member objects is fine in > general, but creates problems when e1 is a reference to the derived > object being constructed If E1 is truely the derived type, the code has undefined behavior. If E1 is an already constructed base class of the derived type, the dynamic type (to which the virtual function resolves) of e1 should be that of the already constructed base class. Undefined behavior if the function is pure virtual in this class; well defined behavior (but not necessarily what is wanted) otherwise. I don't think that this is really any different than calling any other function which calls a virtual function in the already constructed base. The problem in question is getting the correct address for e1. > } > const E1& e1; > const E2& e2; > }; > template < typename F1, typename F2 > struct derived : base1<F1>, > base2<base1<F1>,F2> > { > derived(const F1& f1, const F2& f2): > base1<F1>(f1), > base2<base1<F1>,F2>(*this, f2) //Assume this was legal somehow > {} > virtual void fun() const { cout << "derived fun" << endl; } > }; > The call e1.fun(); would typically get resolved dynamically. > However, in the current case, since we are passing a > reference to an not-yet- completely constructed-object, the > call would get resolved by calling the base1::fun() instead of > derived::fun(). (Of course provided that passing *this in the > constructor of derived class was somehow legal.) Yes. This is well known behavior; it crops up all the time. It surprises newcomers, but after a bit of analysis, it is clear that all of the alternative solutions are worse. > Another example to illustrate this point: > class X > { > public: > X() { } > X(const X& x1, const X& x2) > { > x1.f(); x2.f(); //check if call to f() is resolved dynamically or > not > } > virtual void f() const { std::cout << "base" << std::endl; } > }; > class Z > { > > public: > Z() { } > Z(int m, const X& x) : X(x, *this) //pass two objects of same > type, one completely constructed and one partially constructed. Assume > that passing *this was valid somehow. > { } > virtual void f() const { std::cout << "derived" << std::endl; } > }; > int main() > { > Z z; > Z z2(1, z); //Dummy parameter 1 added, otherwise it will call the > CC. > } > Prints "base" and the "derived", indicating that x.f() is > resolved dynamically but not x2.f(). Both are resolved dynamically. The difference is that when executing X::X(), the dynamic type of the object is X. > However, I doubt if this is "strong" enough reason to disallow > passing (*this) to base class constructor. I don't think that this has anything to do with it. The same "problem" occurs no matter how you call f() in X::X(). The problem is that in some cases, the compiler needs meta-information (from the vtbl or elsewhere in the constructed class) is order to do the derived to base conversion. This information isn't necessarily valid until you've actually entered the body of the constructor of the most derived class. The case of this is different, because 1) the compiler knows that the class is in the process of being constructed, and is not in its final state, and 2) the compiler must be able to make the necessary conversion anyway. -- James Kanze (GABI Software) email: 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 |
|
|
|
|
|||
|
|||
| James Kanze |
|
Alf P. Steinbach
Guest
Posts: n/a
|
* James Kanze:
> On May 6, 1:07 pm, Neelesh <neelesh.bo...@gmail.com> wrote: >> On May 6, 1:51 pm, James Kanze <james.ka...@gmail.com> wrote: >>> On May 6, 6:22 am, Neelesh <neelesh.bo...@gmail.com> wrote: > >>>> On May 6, 5:36 am, huil...@gmail.com wrote: >>>>> Is the following code valid? >>>>> template < typename F > >>>>> struct base1 >>>>> { >>>>> base1(const F& f):f(f){} >>>>> const F& f; >>>>> }; >>>>> template < typename E1, typename E2 > >>>>> struct base2 >>>>> { >>>>> base2(const E1& e1, const E2& e2):e1(e1),e2(e2){} >>>>> const E1& e1; >>>>> const E2& e2; >>>>> }; >>>>> template < typename F1, typename F2 > >>>>> struct derived : base1<F1> >>>>> ,base2<base1<F1>,F2> >>>>> { >>>>> derived(const F1& f1, const F2& f2) >>>>> :base1<F1>(f1) >>>>> ,base2<base1<F1>,F2>(static_cast<base1<F1> const&>(*this), f2) // is >>>>> this okay? >>>>> {} >>>>> }; >>>> Yes, the code is valid and the static_cast is not needed. >>>> 12.6.2p7 >>>> ...because the meminitializer are evaluated in the scope >>>> of the constructor, the this pointer can be used in the >>>> expressionlist of a meminitializer to refer to the object >>>> being initialized. > >>> No, it's not valid. The expression *this is an lvalue >>> expression with type derived. Type derived has a >>> non-trivial constructor. According to §3.8: > >>> [...] The lifetime of an object of type T begins when: > >>> -- storage with the proper alignment and size for type >>> T is obtained, and > >>> -- if T is a class type with a non-trivial constructor >>> (12.1), the constructor call has completed. > >>> Furthermore: > >>> 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 pointer that refers to the >>> storage location where the object will be or was located >>> may be used but only in limited ways. Such a pointer >>> refers to allocated storage (3.7.3.2), and using the >>> pointer as if the pointer were of type void*, is >>> well-defined. Such a pointer may be dereferenced but the >>> resulting lvalue may only be used in limited ways, as >>> described below. If the object will be or was of a class >>> type with a non-trivial destructor, and the pointer is >>> used as the operand of a delete-expression, the program >>> has undefined behavior. If the object will be or was of >>> a non-POD class type, the program has undefined behavior >>> if: > >>> [...] > >>> -- the pointer is used to access a non-static data >>> member or call a non-static member function of the >>> object, or > >>> -- the pointer is implicitly converted (4.10) to a >>> pointer to a base class type, or > >>> -- the pointer is used as the operand of a static_cast >>> (5.2.9) (except when the conversion is to void*, or >>> to void* and subsequently to char*, or unsigned >>> char*). > >>> There's no exception that I can see for the this pointer. > >> hmm...yes..agreed. In fact, in the current case, 3.8p6 applies >> more appropriately: > >> if the original object will be or was of a nonPOD class type, the >> program has undefined behavior if: >> [...] >> — the lvalue is implicitly converted (4.10) to a reference to a base >> class type, or >> [...] > >> The lvalue (*this) has been converted to reference to base >> class type (base<F1>&) in the constructor of derived class, >> which would result in undefined behavior. > >> However, I believe that this is somewhat strange and I donot >> see any obvious reason of not allowing this. > > I can't either. I think the case the standard is trying to > address is that of some external pointer. Something along the > lines of: > > Derived* p = static_cast< Derived* >( > : > new ( p ) Derived ; > > and then the base class constructor calls a function which tries > to convert p to a Base*. There are very good reasons why this > should be undefined behavior. And those reasons really apply to > just about any pointer except this; the compiler can only do the > conversion correctly if it knows (more or less) how much has or > has not been constructed (at least if the base is virtual). AFAICS the compiler doesn't need to know how much has been constructed, but it does need to know location of the base class subobject, which can be a run-time value in the case of a virtual base. This location must be known at the latest when execution of the Derived constructor's body starts, because there Base might be referred to. So what it boils down to is whether a C++ compiler is permitted to allocate a virtual base subobject dynamically, in which case the location might not be known until it has been constructed. I think the base class subobject cannot be dynamically allocated, for reasons that I have partially forgotten but which were convincing to me at the time I analysed this, but as I recall Dave Abrahams thought yes, it can be. Anyway, it seems it's the same situation as with assuming that std::string has a contiguous buffer. Even though the current standard doesn't guarantee that, one would be Really Hard Pressed to find an extant compiler where std::string has a non-contiguous buffer, and likewise, one would be Really Hard Pressed to find a compiler where a virtual base class object is allocated dynamically... And when it's not allocated dynamically, as one can assume for the in-practice, then the compiler has all the information that it needs for the cast -- namely, the offset of the Base subobject relative to any particular Derived object -- at compile time. And it needs to pass that offset so that it's known when execution of the Derived constructor's body starts. So there's then no reason why it can't be available also when the mem initializer list is executed, even for routines called from the mem initializer list, because all the compiler needs to do is to store it wherever general code assumes that it is stored. And so it seems that the standard really should make an exception for the case of up-conversion from Derived of this or *this after execution of a Derived constructor's mem-initializer list has begun. For it's common practice, and it's counter-productive to have compilers warn about it or (as some future compiler might do) outright reject it. And if that turns out to be difficult to get that idea through the politics, then IMHO at least an exception for Derived with no virtual bases. For in that case, as I recall, there's really no problem that isn't already addressed (e.g. one problem is dereferencing a pointer passed elsewhere before relevant part has been constructed, and as I recall that's already addressed). Cheers, - Alf -- Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>. No ads, and there is some C++ stuff! to it is even better! Thanks in advance! |
|
|
|
|
|||
|
|||
| Alf P. Steinbach |
|
|
|
| |
![]() |
| Thread Tools | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| initialization of array as a member using the initialization list | aaragon | C++ | 2 | 11-02-2008 04:57 PM |
| array initialization in initialization list. | toton | C++ | 5 | 09-28-2006 05:13 PM |
| Initialization of non-integral type in initialization list | anongroupaccount@googlemail.com | C++ | 6 | 12-11-2005 09:51 PM |
| Initialization via ctor vs. initialization via assignment | Matthias Kaeppler | C++ | 2 | 07-18-2005 04:25 PM |
| Default Initialization Vs. Value Initialization | JKop | C++ | 10 | 09-22-2004 07:26 PM |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc..
SEO by vBSEO ©2010, Crawlability, Inc. |




