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 t=
wo
different pointers to the same object will always be identical after a=
n
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