Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: efficient swap() when using a custom allocator

It seems to be the month of C++ templates for me...

I have a SecureString. SecureString looks just like a std::string, except it uses a custom allocator which zeroizes on destruction:

class SecureString
{
public:
  typedef std::basic_string< char, std::char_traits<char>, zallocator<char> > SecureStringBase;
  typedef zallocator<char>::size_type size_type;
  static const size_type npos = static_cast<size_type>(-1);
  ....
private:
  SecureStringBase m_base;
};

The full code for SecureString can be found at http://code.google.com/p/owasp-esapi-cplusplus/source/browse/trunk/esapi/util/SecureString.h; and the code for the allocator can be found at http://code.google.com/p/owasp-esapi-cplusplus/source/browse/trunk/esapi/util/zAllocator.h.

Currently, we have a swap defined that takes a std::string as an argument:

void SecureString::swap(std::string& str)
{
  SecureStringBase temp(str.data(), str.size());
  m_base.swap(temp);
  str = std::string(temp.data(), temp.size());
}

I feel like I'm missing an opportunity in swap because the underlying types only differ by allocators. Can anyone see a way to avoid the temporary? Is it possible to use rebind to make this run faster?

EDIT: SecureString::swap(std::string& str) is now gone. Reference to the function in this thread has been left in place for posterity.

Jeff

like image 435
jww Avatar asked Sep 05 '11 03:09

jww


1 Answers

Unfortunately... no.

This is not what rebind is for. rebind is used because an allocator is meant to allocate objects of one type, and one type only (std::allocator<T>) in the STL.

However, there is a trick. When you instantiate std::list<T, std::allocator<T>> for example, then the allocator does not have to allocate Ts, it has to allocate some internal structure instead like __list_node<T>, and that is when rebind is put to use, it creates a new allocator, sibling of the precedent (they differ only by the template parameter and likely share the same memory pool under the covers).

In your case however, your allocator and the std::string allocator are different, and thus they cannot exchange memory. So you have to do a copy.

You can optimize the void swap(SecureString&, SecureString&) operation, but not this one.

One question: why not typedef std::string<char, SecureAllocator<char>> SecureString; ?

like image 101
Matthieu M. Avatar answered Oct 12 '22 23:10

Matthieu M.