| 43 | |
| 44 | === Python crashes if you use an object after deleting an object it was related to === |
| 45 | |
| 46 | Consider this example: |
| 47 | |
| 48 | {{{ |
| 49 | #!python |
| 50 | >>> from osgeo import gdal |
| 51 | >>> dataset = gdal.Open('C:\\RandomData.img') |
| 52 | >>> band = dataset.GetRasterBand(1) |
| 53 | >>> print band.Checksum() |
| 54 | 31212 |
| 55 | }}} |
| 56 | |
| 57 | In this example, {{{band}}} has a relationship with {{{dataset}}} that requires {{{dataset}}} to remain allocated in order for {{{band}}} to work. If we delete {{{dataset}}} and then try to use {{{band}}}, Python will crash: |
| 58 | |
| 59 | {{{ |
| 60 | #!python |
| 61 | >>> from osgeo import gdal |
| 62 | >>> dataset = gdal.Open('C:\\RandomData.img') |
| 63 | >>> band = dataset.GetRasterBand(1) |
| 64 | >>> del dataset # This will cause the Python garbage collector to deallocate dataset |
| 65 | >>> band.GetChecksum() # This will now crash Python because the band's dataset is gone |
| 66 | < Python crashes > |
| 67 | }}} |
| 68 | |
| 69 | This problem can manifest itself in subtle ways. For example, can occur if you try to instantiate a temporary dataset instance within a single line of code: |
| 70 | |
| 71 | {{{ |
| 72 | #!python |
| 73 | >>> from osgeo import gdal |
| 74 | >>> print gdal.Open('C:\\RandomData.img').GetRasterBand(1).Checksum() |
| 75 | < Python crashes > |
| 76 | }}} |
| 77 | |
| 78 | In this example, the dataset instance was no longer needed after the call to {{{GetRasterBand()}}} so Python deallocated it ''before'' calling {{{Checksum()}}}. |
| 79 | |
| 80 | This problem occurs because the GDAL and OGR objects are implemented in C++ and the relationships between them are maintained in C++ using pointers. When you delete the dataset instance in Python it causes the C++ object behind it to be deallocated. But the C++ object behind the band instance does not know that this happened, so it contains a pointer to the C++ dataset object that no longer exists. When the band tries to access the non-existing object, the process crashes. |
| 81 | |
| 82 | The GDAL team knows that this design is not what Python programmers expect. Unfortunately the design is difficult to correct so it is likely to remain for some time. Please consult the GDAL team for more information. |
| 83 | |
| 84 | The problem is not restricted to the GDAL band and dataset objects. It happens in other areas where objects have relationships with each other. Unfortunately there is no complete list, so you have to watch for it yourself. One other known place involves the OGR {{{GetGeometryRef()}}} function: |
| 85 | |
| 86 | {{{ |
| 87 | #!python |
| 88 | >>> feat = lyr.GetNextFeature() |
| 89 | >>> geom = feat.GetGeometryRef() # geom contains a reference into the C++ geometry object maintained by the C++ feature object |
| 90 | >>> del feat # This deallocates the C++ feature object, and its C++ geometry |
| 91 | >>> print(geom.ExportToWkt()) # Crash here. The C++ geometry no longer exists |
| 92 | < Python crashes > |
| 93 | }}} |
| 94 | |
| 95 | If you read the GDAL and OGR API documentation carefully, you will see that the functions that end in "Ref" mention that they transfer ownership of objects. This is a clue that the problem could occur. Be careful when using the "Ref" functions. Also watch out for functions that end in "Directly", such as {{{SetGeometryDirectly()}}}. |
| 96 | |
| 97 | {{{ |
| 98 | #!python |
| 99 | >>> point = ogr.Geometry(ogr.wkbPoint) |
| 100 | >>> feature = ogr.Feature(layer_defn) |
| 101 | >>> feature.SetGeometryDirectly(point) # Transfers ownership of the C++ geometry from point to feature |
| 102 | >>> del feature # point becomes implicitly invalid, because feature owns the C++ geometry |
| 103 | >>> print point.ExportToWkt() # Crash here |
| 104 | < Python crashes > |
| 105 | }}} |
| 106 | |
| 107 | The advantage of the "Ref" and "Directly" functions is they provide faster performance because a duplicate object does not need to be created. The disadvantage is that you have to watch out for this problem. |
| 108 | |
| 109 | The examples here are based on [http://lists.osgeo.org/pipermail/gdal-dev/2010-September/026027.html email from Even Rouault]. |
| 110 | |
| 111 | === Certain objects contain a {{{Destroy()}}} method, but you should never use it === |
| 112 | |
| 113 | |