[Gdal-dev] GDAL CPLError and C++ Exceptions

Mateusz Loskot mateusz at loskot.net
Wed Nov 29 14:57:57 EST 2006


Ray Gardener wrote:
> fwiw, for those preferring exception-based error reporting all around:
> 
> Since GDAL implements return code based error reporting, if you don't
> mind wrapping the GDAL APIs, you can create an exceptions-based
> interface, e.g. if using the GDAL C++ API:
> 
> class GDALDataset_plus
> {
>   public:
>     // After normally instancing a dataset, instance a myDataset
>     // and assign the original dataset to this member var
>     // (or if instancing locally, use the second ctor).
>     GDALDataset* m_pDataset;
> 
>     GDALDataset_plus() : m_pDataset(NULL) {}
>     GDALDataset_plus(GDALDataset* p) : m_pDataset(p) {}
>     virtual ~GDALDataset_plus() { if(m_pDataset) delete m_pDataset; }
> 
>     void AddBand(type, options)
>     {
>         assert_ptr(m_pDataset);
>         if(CE_None != m_pDataset->AddBand(type, options))
>            throw gdal_exception();
>     }
> 
>     // ... wrappers around remaining GDALDataset methods
> };
> 
> // ... GDALxxx_plus class versions of remaining GDAL classes
> 
> 
> And then you can do stuff like:
> 
>   GDALDataset dataset_org;
>   GDALDataset_plus dataset(&dataset_org);

Ray,

This code of usage is ill-formed.
dataset_org is an object with automatic storage duration.
Now, pointer to dataset_org is passed to constructor of
GDALDataset_plus, with implicit *ownership transfer*.
So, it results in m_pDataset pointing to automatic object.

Next, 1) destructor of GDALDataset_plus calls delete on pointer to
automatic object (dataset_org),
2) dataset_org will be destroyed automatically on the scope exit (EOF
object lifetime).

You must not call delete on automatic storage duration objects.

>   try
>   {
>      dataset.AddBand(type, options);
>      // other stuff, with no checking of return codes
>      // since the _plus classes return 'void'
>   }
>   catch(gdal_exception& e) { msg("GDAL exception occurred"); }
>   catch(...) { msg("Unknown error"); }

OK, but the GDALDataset is allocated dynamically and returned by pointer
from GDAL and it needs to be closed and destroyed explicitly by the wrapper.
In the example above, 'dataset' of type of GDALDataset is presented
as local object what's very rare or even impossible situation when using
GDAL.

> The wrappers also enable other niceties, like avoiding having to include
> error variables as arguments (if you always prefer such cases to just
> throw an exception instead), and having the return type of a function
> always be non-error-related. e.g.,
>   int foo(void) instead of errcode foo(int* p)

It's also possible to use smart pointers like shared_ptr with custom
deleter, as a simple wrapper:

boost::shared_ptr<OGRFeature> feature(layer->GetFeature(0),
                                      OGRFeature::DestroyFeature);

Feature object returned by GetFeature will be destroyed properly
by DestroyFeature call.

Cheers
-- 
Mateusz Loskot
http://mateusz.loskot.net



More information about the Gdal-dev mailing list