[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