Pointer class

By Hal Canary, 2013-04-14 12:00:00 (link)

Suppose you are writing a C++ program and are linking to a C library. Many of the library calls return a pointer to a heap-allocated structure. You are expected to free that structure using a specialized free function. For example, the openssl library has a BIGNUM type that is typically created using BN_new() and deleted using BN_free(); The following Pointer< BIGNUM, BN_clear_free > class will take ownership of the BIGNUM pointer in a smart-pointer way and call the BN_free() function when ever the BIGNUM_ptr goes out of scope.

This allows me to exit a function in any of several places (using return or throw) without explicitly freeing memeory.

// Pointer Template
// Copyright 2013 Hal Canary
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef POINTER_H
#define POINTER_H
#include <cstdlib> // std::free(void *)

namespace Pointers {
/**
   A wrapper for the C free function that makes it type-correct. */
template< typename T >
inline void free(T * t_ptr) {
  std::free(static_cast< void * >(t_ptr) );
}

/**
   A wrapper for the C malloc function that makes it type-correct,
   AND multiplies by sizeof(T). */
template< typename T >
inline T * malloc(unsigned int number=1) {
  return static_cast< T * >(std::malloc(number * sizeof(T)));
}
}

/**
   A wrapper for C pointers that makes them smart pointers.

   Example use:
    void f() {
      static const unsigned int N = 100;
      Pointer< char, Pointers::free< char > > str(
        Pointers::malloc< char >(N));
      sprintf( str, "%d = 0x%04x\n", 0x1234, 0x1234);
      std::cout << str;
    } */
template< typename T, void (*F)( T *) >
class Pointer {
private:
  T * m_ptr;
  Pointer(const Pointer &) { /* disallowed */}
public:
  Pointer ( T * ptr=NULL )
    : m_ptr(ptr) { }
  ~Pointer () {
    if (m_ptr)
      F(m_ptr);
  }
  Pointer & operator=(T * ptr) {
    if (m_ptr)
      F(m_ptr);
    m_ptr = ptr;
    return *this;
  }
  operator T * () { return m_ptr; }
  operator T * () const { return m_ptr; }
  bool operator!() const { return (! m_ptr); }
  T ** operator&() { return &m_ptr; }
  T ** operator&() const { return &m_ptr; }
  T * operator->() { return m_ptr; }
  T * operator->() const { return m_ptr; }
};

#endif /* POINTER_H */

And the main funtion, as promised:

// compile with "-lcrypto"
#include <iostream> // cout
#include <exception> // exception
#include <openssl/bn.h> // BIGNUM
#include "Pointer.h" // Pointer
/**
   Convert a long hexidecimal number to decimal. */
int main(int, char **) {
  const char hexnumber[]
    = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
  Pointer< BIGNUM, BN_clear_free > bn(NULL);
  if (! BN_hex2bn(&(bn), hexnumber))
    throw std::exception();
  Pointer< char, Pointers::free< char > > dec(BN_bn2dec(bn));
  std::cout << dec << '\n';
  return 0;
}

(back)