Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Is a function argument an implicit cast?

Reply
Thread Tools

Is a function argument an implicit cast?

 
 
DeMarcus
Guest
Posts: n/a
 
      03-03-2010
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
 
Reply With Quote
 
 
 
 
Michael Doubez
Guest
Posts: n/a
 
      03-03-2010
On 3 mar, 12:48, DeMarcus <(E-Mail Removed)> 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
 
Reply With Quote
 
 
 
 
DeMarcus
Guest
Posts: n/a
 
      03-03-2010
Michael Doubez wrote:
> On 3 mar, 12:48, DeMarcus <(E-Mail Removed)> 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?
 
Reply With Quote
 
Michael Doubez
Guest
Posts: n/a
 
      03-03-2010
On 3 mar, 15:15, DeMarcus <(E-Mail Removed)> wrote:
> Michael Doubez wrote:
> > On 3 mar, 12:48, DeMarcus <(E-Mail Removed)> 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
 
Reply With Quote
 
DeMarcus
Guest
Posts: n/a
 
      03-03-2010
>
> 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.
 
Reply With Quote
 
Michael Doubez
Guest
Posts: n/a
 
      03-03-2010
On 3 mar, 19:08, "Leigh Johnston" <(E-Mail Removed)> 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
 
Reply With Quote
 
DeMarcus
Guest
Posts: n/a
 
      03-03-2010
Michael Doubez wrote:
> On 3 mar, 19:08, "Leigh Johnston" <(E-Mail Removed)> 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?




 
Reply With Quote
 
Michael Tsang
Guest
Posts: n/a
 
      03-04-2010
DeMarcus wrote:

> Michael Doubez wrote:
>> On 3 mar, 19:08, "Leigh Johnston" <(E-Mail Removed)> 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.
 
Reply With Quote
 
Michael Doubez
Guest
Posts: n/a
 
      03-04-2010
On 4 mar, 09:46, Michael Tsang <(E-Mail Removed)> wrote:
> DeMarcus wrote:
> > Michael Doubez wrote:
> >> On 3 mar, 19:08, "Leigh Johnston" <(E-Mail Removed)> 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
 
Reply With Quote
 
DeMarcus
Guest
Posts: n/a
 
      03-04-2010
Michael Doubez wrote:
> On 4 mar, 09:46, Michael Tsang <(E-Mail Removed)> wrote:
>> DeMarcus wrote:
>>> Michael Doubez wrote:
>>>> On 3 mar, 19:08, "Leigh Johnston" <(E-Mail Removed)> 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!
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Variable argument function as a parameter of a variable argument function AikidoGuy C Programming 11 11-21-2011 10:43 PM
How to code an implicit $_ argument? Tim McDaniel Perl Misc 15 08-23-2009 11:25 PM
function argument dependent on another function argument? Reckoner Python 11 01-19-2009 03:31 AM
Function pointers, variable argument functions calling other variable-argument functions (sort of) S?ren Gammelmark C Programming 1 01-07-2005 09:41 PM
How to pass variable argument list to another function w/ variable argument list? Ben Kial C Programming 1 11-15-2004 01:51 AM



Advertisments