Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Is a function argument an implicit cast? (http://www.velocityreviews.com/forums/t716599-is-a-function-argument-an-implicit-cast.html)

DeMarcus 03-03-2010 11:48 AM

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

Michael Doubez 03-03-2010 01:10 PM

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

DeMarcus 03-03-2010 02:15 PM

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?

Michael Doubez 03-03-2010 03:01 PM

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

DeMarcus 03-03-2010 05:09 PM

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.

Michael Doubez 03-03-2010 08:20 PM

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

DeMarcus 03-03-2010 10:06 PM

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?





Michael Tsang 03-04-2010 08:46 AM

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.

Michael Doubez 03-04-2010 09:06 AM

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

DeMarcus 03-04-2010 11:01 AM

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 11:40 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.