[fdo-dev] Pre-conditions and unsafe constuctions
Brent Robinson
brent.robinson at autodesk.com
Thu Dec 7 12:45:20 EST 2006
Hi Mateusz,
The SmartCast function is mainly a convenience function for handling
assignments between FdoPtr's on classes that are different but based on
each other, and hiding the refcount adjustments that must be done for
these assignments. In the FdoRdbmsMySqlConnection::NewSchemaManager()
example, a straight assignment:
FdoSmPhMySqlMgrP physMgr = schMgr->GetPhysicalSchema();
fails to compile. Something like the following would work:
FdoSmPhMySqlMgrP physMgr =
FDO_SAFE_ADDREF(dynamic_cast<FdoSmPhMySqlMgr*>((FdoSmPhMgr*)
schMgr->GetPhysicalSchema());
Or even better:
FdoSmPhMySqlMgrP physMgr =
FDO_SAFE_ADDREF(static_cast<FdoSmPhMySqlMgr*>((FdoSmPhMgr*)
schMgr->GetPhysicalSchema());
However, the reference held by physMgr on the underlying object has to
be done by an explicit Addref. The SmartCast function encapsulates this
Addref so it makes the line a bit shorter:
FdoSmPhMySqlMgrP physMgr =
schMgr->GetPhysicalSchema()->SmartCast<FdoSmPhMySqlMgr>();
SmartCast returns NULL pointers, rather than throwing an exception when
the pointer can't be cast, because it is used in other situations to
test the type of an object.
For example, the FdoSmPhDbObjectCollection contains a collection of
database objects, which can be tables or views. To perform an operation
on each table in the collection (skipping any non-tables), the following
can be done:
ProcessTables( FdoSmPhDbObjectsP dbObjects )
{
for ( int i = 0; i < dbObjects->GetCount(); i++ )
{
FdoSmPhDbObjectP dbObject = dbObjects->GetItem(i);
FdoSmPhTableP table = dbObject->GetItem(i)
->SmartCast<FdoSmPhTable>();
if ( table )
... do something
}
}
There have been some discussions about implementing something at the
FdoPtr level to handle such assignments with up or down casting but I
don't believe anything has been done yet, so in the meantime the Schema
Manager makes use of SmartCast.
Another feature of SmartCast is that it allows an FdoPtr for a specific
type to wrap around a regular pointer of a base type and release the
pointer if it is not of the specific type. This is done by setting the
wraparound parameter to true. This reduces the above table processing to
the following:
ProcessTables( FdoSmPhDbObjectsP dbObjects )
{
for ( int i = 0; i < dbObjects->GetCount(); i++ )
{
FdoSmPhTableP table = dbObjects->GetItem(i)
->SmartCast<FdoSmPhTable>(true);
if ( table )
... do something
}
}
In this case when dbObjects->GetItem(i) returns a table, the table
FdoPtr just wraps around it (GetItem() already did the AddRef). When it
returns a view, table is set to NULL, and SmartCast release the object
returned by GetItem().
In the case of where SmartCast is used in
FdoRdbmsMySqlConnection::NewSchemaManager(), it is true that the
exception thrown, when GetPhysicalSchema() does not return an
FdoSmPhMySqlMgr, will not be precise as it could be. This could be
remedied by adding a check for NULL or creating another variant of
SmartCast that throws an exception when the object can't be cast.
If you want, you can used static_cast or dynamic_cast, instead of
SmartCast, though you'll need to handle the reference count adjusting on
your own, when casting between different types of FdoPtr's. Where
possible, static_cast should be used instead of dynamic_cast. On Linux,
there is a bug where a dynamic_cast on a class from a shared library,
not explicity linked against the library or executable where the cast is
performed, will always return NULL.
-----Original Message-----
From: Mateusz Loskot [mailto:mateusz at loskot.net]
Sent: Thursday, December 07, 2006 10:54 AM
To: dev at fdo.osgeo.org
Subject: Re: [fdo-dev] Pre-conditions and unsafe constuctions
Hi,
Here is another construction I'd like to get some explanation about.
In function FdoRdbmsMySqlConnection::NewSchemaManager(), there is
following construction:
FdoSmPhMySqlMgrP physMgr =
schMgr->GetPhysicalSchema()->SmartCast<FdoSmPhMySqlMgr>();
According to my understanding of the SmartCast<T>() implemen,
it is acceptable to return NULL from this call.
Next, FdoSmPhMgrP (FdoPtr-based type) is initialized with NULL.
Again, FdoPtr<T>::operator-> will throw "encrypted" exception not
explaining the real problem: Type of FdpoSmPhMgr is not castable
to FdoSmPhMySqlMgr type, what in turn means a real design
problem occured.
Why SmartCast<T>() function, if present anyway, does not check for
NULL and throw domain-related error like "Types are unrelated and can
not be downcasted" or similar?
Otherwise, I can't see the real benefits of SmartCast<T>() and even it
makes code error prone, because it allows chain-calls of operator->()
without having real control on pointers validation.
I'm just curious about rationale of these constructions and I wonder if
I am allowed to not to use SmartCast and DownCast functions in PostGIS
provider but use dynamic_cast and throw some FDO exception if types are
unrelated so not castable.
Am I allowed?
Cheers
--
Mateusz Loskot
http://mateusz.loskot.net
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe at fdo.osgeo.org
For additional commands, e-mail: dev-help at fdo.osgeo.org
More information about the Fdo-internals
mailing list