![]() |
Is a function argument an implicit cast?
Hi.
I need to store pointers as void* to be able to check that an (semi-arbitrary) object cannot be used twice. It looks like this. template<typename T> class BaseClass { T t; }; std::set<const void*> checklist; template<typename T> bool testAndSet( const BaseClass<T>& object ) { // Insert object into set, if already inserted, return false. return checklist.insert( &object ).second; } int main() { BaseClass<int> intClass; assert( testAndSet( intClass ) && "Should not fail" ); assert( testAndSet( intClass ) && "Should fail" ); } Regarding the conversion to const void* when inserting into the set, this must be safe, right? Since everything that comes into testAndSet() are implicitly cast to BaseClass<T> the void* must always be the same for any single object. In a previous post Alf P. Steinbach showed the following problem. struct A { int a; }; struct B : A { virtual ~B() {} int b; }; int main() { B* p1 = new B; A* p2 = p1; void* pv1 = p1; void* pv2 = p2; assert( pv1 == pv2 && "Fails!" ); } But isn't my example safe from that since I do an implicit cast in the function argument, similar to doing the following. int main() { B* p1 = new B; A* p2 = p1; void* pv1 = static_cast<A*>(p1); void* pv2 = static_cast<A*>(p2); assert( pv1 == pv2 && "Should be ok" ); } Am I correct about this assumption? Does it say in the standard that two different pointers to the same object will always be identical after an implicit cast through a function call like my testAndSet example above? Thanks, Daniel |
Re: Is a function argument an implicit cast?
On 3 mar, 12:48, DeMarcus <use_my_alias_h...@hotmail.com> wrote:
> Hi. > > I need to store pointers as void* to be able to check that an > (semi-arbitrary) object cannot be used twice. > > It looks like this. > > template<typename T> > class BaseClass > { > * * T t; > > }; > > std::set<const void*> checklist; > > template<typename T> > bool testAndSet( const BaseClass<T>& object ) > { > * * // Insert object into set, if already inserted, return false. > * * return checklist.insert( &object ).second; > > } > > int main() > { > * * BaseClass<int> intClass; > * * assert( testAndSet( intClass ) && "Should not fail" ); > * * assert( testAndSet( intClass ) && "Should fail" ); > > } > > Regarding the conversion to const void* when inserting into the set, > this must be safe, right? Yes. It is safe. > Since everything that comes into testAndSet() > are implicitly cast to BaseClass<T> the void* must always be the same > for any single object. It will be the same for any single address. This is equivalent to a reinterpret_cast<void*>(). If you want it to be the same for any single object, you must use a dynamic_cast<void*>(). You will the have a pointer on the most derived underlying object. > In a previous post Alf P. Steinbach showed the following problem. > > struct A > { > * * int a; > > }; > > struct B : A > { > * * virtual ~B() {} > * * int b; > > }; > > int main() > { > * * B* p1 = new B; > * * A* p2 = p1; > * * void* pv1 = p1; > * * void* pv2 = p2; > * * assert( pv1 == pv2 && "Fails!" ); > > } > > But isn't my example safe from that since I do an implicit cast in the > function argument, similar to doing the following. > > int main() > { > * * B* p1 = new B; > * * A* p2 = p1; > * * void* pv1 = static_cast<A*>(p1); > * * void* pv2 = static_cast<A*>(p2); > * * assert( pv1 == pv2 && "Should be ok" ); > > } > > Am I correct about this assumption? Does it say in the standard that two > different pointers to the same object will always be identical after an > implicit cast through a function call like my testAndSet example above? If you are guaranteed that you have only one ancestor, yes but see the problem: struct A { int a; }; struct B : A { virtual ~B() {} int b; }; struct C : A { virtual ~C() {} int c; }; struct D : B, C { virtual ~D() {} int d; }; main() { C* p1 = new C; A* p2 = p1; B* p3 = p1; void* pv1 = static_cast<A*>(p2); void* pv2 = static_cast<A*>(p3); assert( pv1 == pv2 && "Should Fail" ); } -- Michael |
Re: Is a function argument an implicit cast?
Michael Doubez wrote:
> On 3 mar, 12:48, DeMarcus <use_my_alias_h...@hotmail.com> wrote: >> Hi. >> >> I need to store pointers as void* to be able to check that an >> (semi-arbitrary) object cannot be used twice. >> >> It looks like this. >> >> template<typename T> >> class BaseClass >> { >> T t; >> >> }; >> >> std::set<const void*> checklist; >> >> template<typename T> >> bool testAndSet( const BaseClass<T>& object ) >> { >> // Insert object into set, if already inserted, return false. >> return checklist.insert( &object ).second; >> >> } >> >> int main() >> { >> BaseClass<int> intClass; >> assert( testAndSet( intClass ) && "Should not fail" ); >> assert( testAndSet( intClass ) && "Should fail" ); >> >> } >> >> Regarding the conversion to const void* when inserting into the set, >> this must be safe, right? > > Yes. It is safe. > >> Since everything that comes into testAndSet() >> are implicitly cast to BaseClass<T> the void* must always be the same >> for any single object. > > It will be the same for any single address. This is equivalent to a > reinterpret_cast<void*>(). > > If you want it to be the same for any single object, you must use a > dynamic_cast<void*>(). You will the have a pointer on the most derived > underlying object. > > >> In a previous post Alf P. Steinbach showed the following problem. >> >> struct A >> { >> int a; >> >> }; >> >> struct B : A >> { >> virtual ~B() {} >> int b; >> >> }; >> >> int main() >> { >> B* p1 = new B; >> A* p2 = p1; >> void* pv1 = p1; >> void* pv2 = p2; >> assert( pv1 == pv2 && "Fails!" ); >> >> } >> >> But isn't my example safe from that since I do an implicit cast in the >> function argument, similar to doing the following. >> >> int main() >> { >> B* p1 = new B; >> A* p2 = p1; >> void* pv1 = static_cast<A*>(p1); >> void* pv2 = static_cast<A*>(p2); >> assert( pv1 == pv2 && "Should be ok" ); >> >> } >> >> Am I correct about this assumption? Does it say in the standard that two >> different pointers to the same object will always be identical after an >> implicit cast through a function call like my testAndSet example above? > > If you are guaranteed that you have only one ancestor, yes but see the > problem: > > struct A > { > int a; > }; > > struct B : A > { > virtual ~B() {} > int b; > }; > > > struct C : A > { > virtual ~C() {} > int c; > }; > > struct D : B, C > { > virtual ~D() {} > int d; > }; > > > main() > { > C* p1 = new C; > A* p2 = p1; > B* p3 = p1; > void* pv1 = static_cast<A*>(p2); > void* pv2 = static_cast<A*>(p3); > assert( pv1 == pv2 && "Should Fail" ); > } > > -- > Michael B* p3 = p1; will give a compiler error, which is fine. I guess you meant the following. main() { D* p1 = new D; // <-- D instead C* p2 = p1; B* p3 = p1; void* pv1 = static_cast<A*>(p2); void* pv2 = static_cast<A*>(p3); assert( pv1 == pv2 && "Should Fail" ); } What does the standard say about such cast? |
Re: Is a function argument an implicit cast?
On 3 mar, 15:15, DeMarcus <use_my_alias_h...@hotmail.com> wrote:
> Michael Doubez wrote: > > On 3 mar, 12:48, DeMarcus <use_my_alias_h...@hotmail.com> wrote: > >> Hi. > > >> I need to store pointers as void* to be able to check that an > >> (semi-arbitrary) object cannot be used twice. > > >> It looks like this. > > >> template<typename T> > >> class BaseClass > >> { > >> * * T t; > > >> }; > > >> std::set<const void*> checklist; > > >> template<typename T> > >> bool testAndSet( const BaseClass<T>& object ) > >> { > >> * * // Insert object into set, if already inserted, return false. > >> * * return checklist.insert( &object ).second; > > >> } > > >> int main() > >> { > >> * * BaseClass<int> intClass; > >> * * assert( testAndSet( intClass ) && "Should not fail" ); > >> * * assert( testAndSet( intClass ) && "Should fail" ); > > >> } > > >> Regarding the conversion to const void* when inserting into the set, > >> this must be safe, right? > > > Yes. It is safe. > > >> Since everything that comes into testAndSet() > >> are implicitly cast to BaseClass<T> the void* must always be the same > >> for any single object. > > > It will be the same for any single address. This is equivalent to a > > reinterpret_cast<void*>(). > > > If you want it to be the same for any single object, you must use a > > dynamic_cast<void*>(). You will the have a pointer on the most derived > > underlying object. > > >> In a previous post Alf P. Steinbach showed the following problem. > > >> struct A > >> { > >> * * int a; > > >> }; > > >> struct B : A > >> { > >> * * virtual ~B() {} > >> * * int b; > > >> }; > > >> int main() > >> { > >> * * B* p1 = new B; > >> * * A* p2 = p1; > >> * * void* pv1 = p1; > >> * * void* pv2 = p2; > >> * * assert( pv1 == pv2 && "Fails!" ); > > >> } > > >> But isn't my example safe from that since I do an implicit cast in the > >> function argument, similar to doing the following. > > >> int main() > >> { > >> * * B* p1 = new B; > >> * * A* p2 = p1; > >> * * void* pv1 = static_cast<A*>(p1); > >> * * void* pv2 = static_cast<A*>(p2); > >> * * assert( pv1 == pv2 && "Should be ok" ); > > >> } > > >> Am I correct about this assumption? Does it say in the standard that two > >> different pointers to the same object will always be identical after an > >> implicit cast through a function call like my testAndSet example above? > > > If you are guaranteed that you have only one ancestor, yes but see the > > problem: > > > struct A > > { > > * * int a; > > }; > > > struct B : A > > { > > * * virtual ~B() {} > > * * int b; > > }; > > > struct C : A > > { > > * * virtual ~C() {} > > * * int c; > > }; > > > struct D : B, C > > { > > * * virtual ~D() {} > > * * int d; > > }; > > > main() > > { > > * * C* p1 = new C; > > * * A* p2 = p1; > > * * B* p3 = p1; > > * * void* pv1 = static_cast<A*>(p2); > > * * void* pv2 = static_cast<A*>(p3); > > * * assert( pv1 == pv2 && "Should Fail" ); > > } > > > -- > > Michael > > B* p3 = p1; will give a compiler error, which is fine. > I guess you meant the following. > > main() > { > * * D* p1 = new D; // <-- D instead > * * C* p2 = p1; > * * B* p3 = p1; > * * void* pv1 = static_cast<A*>(p2); > * * void* pv2 = static_cast<A*>(p3); > * * assert( pv1 == pv2 && "Should Fail" ); > > } Yes, that's what I meant. > What does the standard say about such cast? pv1 will point to D::C::A of p1 and pv2 will point to D::B::A of p1 (unless you sue virtual inheritance). So you have pv1 != pv2. I hinted that with dynamic_cast<void*>() you get a pointer on the most derived class. IMO, this is what you are looking for. In the example: void* pa1 = static_cast<A*>(p2); void* pa2 = static_cast<A*>(p3); void* pv1 = dynamic_cast<void*>(pa1); void* pv2 = dynamic_cast<void*>(pa2); assert( pv1 == pv2 && "Should Succeed" ); -- Michael |
Re: Is a function argument an implicit cast?
>
> pv1 will point to D::C::A of p1 and pv2 will point to D::B::A of p1 > (unless you sue virtual inheritance). So you have pv1 != pv2. > > I hinted that with dynamic_cast<void*>() you get a pointer on the most > derived class. IMO, this is what you are looking for. In the example: > > void* pa1 = static_cast<A*>(p2); > void* pa2 = static_cast<A*>(p3); > > void* pv1 = dynamic_cast<void*>(pa1); > void* pv2 = dynamic_cast<void*>(pa2); > > assert( pv1 == pv2 && "Should Succeed" ); > Yes, that's true. However, in case I do not have a diamond shaped non-virtual multiple inheritance as the example above, where in the standard can I find that a static_cast or implicit function cast always will yield the same pointer for an arbitrary class hierarchy? I want to put that as a comment in the code. I tried to browse the standard to find it but if someone knows where to look I would appreciate it a lot. |
Re: Is a function argument an implicit cast?
On 3 mar, 19:08, "Leigh Johnston" <le...@i42.co.uk> wrote:
> > I hinted that with dynamic_cast<void*>() you get a pointer on the most > > derived class. IMO, this is what you are looking for. In the example: > > > void* pa1 = static_cast<A*>(p2); > > void* pa2 = static_cast<A*>(p3); > > > void* pv1 = dynamic_cast<void*>(pa1); > > void* pv2 = dynamic_cast<void*>(pa2); > > > assert( pv1 == pv2 && "Should Succeed" ); > > This won't work as dynamic_cast requires polymorphic types, pa1 and pa2 are > void* pointers (not polymorphic), if you meant pa1 and pa2 to be A* pointers Yes, that's what I meant. > it still won't work as A is not polymorphic. What do you mean ? A doesn't need to be polymorphic for dynamic_cast<> to work. -- Michael |
Re: Is a function argument an implicit cast?
Michael Doubez wrote:
> On 3 mar, 19:08, "Leigh Johnston" <le...@i42.co.uk> wrote: >>> I hinted that with dynamic_cast<void*>() you get a pointer on the most >>> derived class. IMO, this is what you are looking for. In the example: >>> void* pa1 = static_cast<A*>(p2); >>> void* pa2 = static_cast<A*>(p3); >>> void* pv1 = dynamic_cast<void*>(pa1); >>> void* pv2 = dynamic_cast<void*>(pa2); >>> assert( pv1 == pv2 && "Should Succeed" ); >> This won't work as dynamic_cast requires polymorphic types, pa1 and pa2 are >> void* pointers (not polymorphic), if you meant pa1 and pa2 to be A* pointers > > Yes, that's what I meant. > >> it still won't work as A is not polymorphic. > > What do you mean ? A doesn't need to be polymorphic for dynamic_cast<> > to work. > Actually, yes. According to the standard, it says nothing about that demand, but according to my compiler (gcc 4.4.1) it gives an error if A is not polymorphic. Something is wrong, I agree. Is it because there is no vtable in A? |
Re: Is a function argument an implicit cast?
DeMarcus wrote:
> Michael Doubez wrote: >> On 3 mar, 19:08, "Leigh Johnston" <le...@i42.co.uk> wrote: >>>> I hinted that with dynamic_cast<void*>() you get a pointer on the most >>>> derived class. IMO, this is what you are looking for. In the example: >>>> void* pa1 = static_cast<A*>(p2); >>>> void* pa2 = static_cast<A*>(p3); >>>> void* pv1 = dynamic_cast<void*>(pa1); >>>> void* pv2 = dynamic_cast<void*>(pa2); >>>> assert( pv1 == pv2 && "Should Succeed" ); >>> This won't work as dynamic_cast requires polymorphic types, pa1 and pa2 >>> are void* pointers (not polymorphic), if you meant pa1 and pa2 to be A* >>> pointers >> >> Yes, that's what I meant. >> >>> it still won't work as A is not polymorphic. >> >> What do you mean ? A doesn't need to be polymorphic for dynamic_cast<> >> to work. >> > > Actually, yes. According to the standard, it says nothing about that > demand, but according to my compiler (gcc 4.4.1) it gives an error if A > is not polymorphic. > > Something is wrong, I agree. Is it because there is no vtable in A? The standard does say that to cast from base to derived needs a virtual function in base. (ISO/IEC 14882:2003 Section 5.2.7 Dynamic cast [expr.dynamic.cast] 1 The result of the expression dynamic_cast<T>(v) (omitted) 2 (omitted) 3 If the type of v is the same as the required result type (omitted), or it is the same as R except that the class object type in R is move cv-qualified than the class object type in v, (omitted) 4 (omitted) 5 If T is "pointer to cv1 B" and v has type "pointer to cv2 D" such that B is a base class of D, (omitted) 6 Otherwise, v shall be a pointer to or an lvalue of a *polymorphic* type. |
Re: Is a function argument an implicit cast?
On 4 mar, 09:46, Michael Tsang <mikl...@gmail.com> wrote:
> DeMarcus wrote: > > Michael Doubez wrote: > >> On 3 mar, 19:08, "Leigh Johnston" <le...@i42.co.uk> wrote: > >>>> I hinted that with dynamic_cast<void*>() you get a pointer on the most > >>>> derived class. IMO, this is what you are looking for. In the example: > >>>> void* pa1 = static_cast<A*>(p2); > >>>> void* pa2 = static_cast<A*>(p3); > >>>> void* pv1 = dynamic_cast<void*>(pa1); > >>>> void* pv2 = dynamic_cast<void*>(pa2); > >>>> assert( pv1 == pv2 && "Should Succeed" ); > >>> This won't work as dynamic_cast requires polymorphic types, pa1 and pa2 > >>> are void* pointers (not polymorphic), if you meant pa1 and pa2 to be A* > >>> pointers > > >> Yes, that's what I meant. > > >>> it still won't work as A is not polymorphic. > > >> What do you mean ? A doesn't need to be polymorphic for dynamic_cast<> > >> to work. > > > Actually, yes. According to the standard, it says nothing about that > > demand, but according to my compiler (gcc 4.4.1) it gives an error if A > > is not polymorphic. > > > Something is wrong, I agree. Is it because there is no vtable in A? > > The standard does say that to cast from base to derived needs a virtual > function in base. (ISO/IEC 14882:2003 Section 5.2.7 Dynamic cast > [expr.dynamic.cast] > > 1 The result of the expression dynamic_cast<T>(v) (omitted) > 2 (omitted) > 3 If the type of v is the same as the required result type (omitted), or it > is the same as R except that the class object type in R is move cv-qualified > than the class object type in v, (omitted) > 4 (omitted) > 5 If T is "pointer to cv1 B" and v has type "pointer to cv2 D" such that B > is a base class of D, (omitted) > 6 Otherwise, v shall be a pointer to or an lvalue of a *polymorphic* type. OK. The RTTI information is not generated if A is not polymorphic (or without a specific compiler option or pragma) and dynamic_cast<>() will fail. Well. Easy enough to fix - use a virtual destructor. -- Michael |
Re: Is a function argument an implicit cast?
Michael Doubez wrote:
> On 4 mar, 09:46, Michael Tsang <mikl...@gmail.com> wrote: >> DeMarcus wrote: >>> Michael Doubez wrote: >>>> On 3 mar, 19:08, "Leigh Johnston" <le...@i42.co.uk> wrote: >>>>>> I hinted that with dynamic_cast<void*>() you get a pointer on the most >>>>>> derived class. IMO, this is what you are looking for. In the example: >>>>>> void* pa1 = static_cast<A*>(p2); >>>>>> void* pa2 = static_cast<A*>(p3); >>>>>> void* pv1 = dynamic_cast<void*>(pa1); >>>>>> void* pv2 = dynamic_cast<void*>(pa2); >>>>>> assert( pv1 == pv2 && "Should Succeed" ); >>>>> This won't work as dynamic_cast requires polymorphic types, pa1 and pa2 >>>>> are void* pointers (not polymorphic), if you meant pa1 and pa2 to be A* >>>>> pointers >>>> Yes, that's what I meant. >>>>> it still won't work as A is not polymorphic. >>>> What do you mean ? A doesn't need to be polymorphic for dynamic_cast<> >>>> to work. >>> Actually, yes. According to the standard, it says nothing about that >>> demand, but according to my compiler (gcc 4.4.1) it gives an error if A >>> is not polymorphic. >>> Something is wrong, I agree. Is it because there is no vtable in A? >> The standard does say that to cast from base to derived needs a virtual >> function in base. (ISO/IEC 14882:2003 Section 5.2.7 Dynamic cast >> [expr.dynamic.cast] >> >> 1 The result of the expression dynamic_cast<T>(v) (omitted) >> 2 (omitted) >> 3 If the type of v is the same as the required result type (omitted), or it >> is the same as R except that the class object type in R is move cv-qualified >> than the class object type in v, (omitted) >> 4 (omitted) >> 5 If T is "pointer to cv1 B" and v has type "pointer to cv2 D" such that B >> is a base class of D, (omitted) >> 6 Otherwise, v shall be a pointer to or an lvalue of a *polymorphic* type. > > > OK. The RTTI information is not generated if A is not polymorphic (or > without a specific compiler option or pragma) and dynamic_cast<>() > will fail. > > Well. Easy enough to fix - use a virtual destructor. > Yes, thanks! |
| All times are GMT. The time now is 09:47 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.