[gdal-dev] Simplifying malloc'action with simple templates

Philippe Vachon philippe at cowpig.ca
Sat Jan 9 16:05:00 EST 2010


Hi Mateusz,

I would actually wonder if a solution like this would work:

/// @brief Allocate memory on the heap and return a pointer of type T.
/// @param ptr pointer to be populated to the allocated memory
/// @param size the size of a single object to be allocated (or of the entire region)
/// @param nmemb optional, the number of regions to be allocated. The resulting region would be size * nmemb.
/// ...
template <typename T>
T *CPLMallocT(T*& ptr, std::size_t const size = sizeof(T), std::size_t const nmemb = 1) { ... }

This would enable replacing the VSIMalloc* routines (the ones that check for argument wraparound) with a single unified interface, and implicitly enable the last version of CPLMallocT that you proposed. So long as malloc() is still used under the hood, I presume {VSI,CPL}Free() will still behave as before.

Cheers,
Phil

On 2010-01-09, at 3:19 PM, Mateusz Loskot wrote:

> Folks,
> 
> The CPLMalloc and related functions are widely settled, but as
> wrappers on std::malloc, they do not make it simpler to use in C++
> files, so GDAL code could be more readable. These functions
> still require explicit casts.
> 
> It is possible to simplify use of them, at least in source files
> compiled in C++ mode, by introducing some
> 
> /// Option 1 ///////////////////////////////////////////////////////
> 
> template <typename T>
> T* CPLMallocT(std::size_t const size)
> {
>    // sizeof(T) * size or al size
>    return static_cast<T*>(CPLMalloc(size(T) * size));
> }
> 
> It's usage gets rid of cast, but still requires type
> specified explicitly:
> 
> T* p = CPLMallocT<T>(20);
> 
> Another variation if flexibility of size of allocation is needed:
> 
> template <typename T>
> T* CPLMallocT(std::size_t const n, std::size_t const size = sizeof(T))
> {
>    return static_cast<T*>(CPLMalloc(n * size));
> }
> 
> int* p1 = CPLMallocT<int>(10);
> int* p2 = CPLMallocT<int>(10, 4);
> 
> // Option 2 ///////////////////////////////////////////////////////
> 
> template <typename T>
> void CPLMallocT(T*& ptr, std::size_t const size)
> {
>    ptr = static_cast<T*>(CPLMalloc(sizeof(T) * size));
> }
> 
> 
> It removes cast as well as type is resolved by compiler
> 
> CPLMallocT(p, 10);
> 
> 
> // Option 3 ///////////////////////////////////////////////////////
> 
> template <typename T>
> T*& CPLMallocT(T*& ptr, std::size_t const size)
> {
>    ptr = static_cast<T*>(std::malloc(sizeof(T) * size));
>    return ptr;
> }
> 
> This one works as combination of the two above,
> removes cast, resolves type, but here pointer is passed
> as extra argument to the function:
> 
> T* p = 0;
> 
> p = CPLMallocT(p, 10);
> 
> or
> 
> CPLMallocT(p, 10);
> 
> 
> IMHO, such functions simplify allocation call, make code more readable,
> prevent from spreading large number of casts around by keeping it in
> single place. It also may simplify further maintenance, if option 3 is
> used, because if T changes, it enough to type of pointer in place of its
> declaration, i.e. float* to double* for array.
> 
> 
> 
> Yet another version CPLMallocT could take no argument but type only:
> 
> template <typename T>
> T* CPLMallocT()
> {
>    return static_cast<T*>(CPLMalloc(size(T)));
> }
> 
> then allocation like this:
> 
> cur = (GDALProxyPoolCacheEntry*) CPLMalloc(sizeof(GDALProxyPoolCacheEntry));
> 
> becomes
> 
> cur = CPLMallocT<GDALProxyPoolCacheEntry>();
> 
> 
> The latter is simpler and intentions are more obvious to
> reader - allocate memory for single of object of given type.
> 
> If there would be interest in such utilities, I can commit it to
> trunk and refactor code.
> 
> Best regards,
> -- 
> Mateusz Loskot, http://mateusz.loskot.net
> Charter Member of OSGeo, http://osgeo.org
> _______________________________________________
> gdal-dev mailing list
> gdal-dev at lists.osgeo.org
> http://lists.osgeo.org/mailman/listinfo/gdal-dev



More information about the gdal-dev mailing list