Data Class

[C++]

class Data
{
public:
  Data(BSTR bstr, bool owner = true);
  Data(unsigned char const* ptr, unsigned int size);
  Data(unsigned int size = 0);        // Object writable if size != 0
  Data(Data const& data);             // Both objects become unwritable
  ~Data() { Resize(0); }

  void Resize(unsigned int size);     // Object writable if size != 0
  Data& operator=(Data const& data);  // Both objects become unwritable

  unsigned char* GetWritablePtr();
  unsigned char const* GetPtr() const;
  unsigned int GetSize() const;
}

Members

Creation, Assignment, Resizing

  • (1) Data: Constructs Data from a BSTR.
    Ownership: Depends on the owner parameter.
    Parameters:
    • bstr: A BSTR containing the data to wrap.
    • owner: Should we become the owner of the BSTR? The owner is responsible for calling SysFreeString.
  • (2) Data: Constructs Data from a unsigned char (=byte) array.
    Ownership: Not owned.
    Parameters:
    • ptr: An array of type unsigned char (=byte) that should be wrapped.
    • size: Size of the array in bytes.
  • (3) Data: Creates an empty writable data object.
    Ownership: Owned.
    Parameters:
    • size: Size of the data array in bytes.
  • (4) Data: Copy constructor.
    Ownership: *
    Parameters:
    • data: Another Data object.

  • ~Data: Destructor. If owner, it frees the wrapped BSTR rendering all pointers to the data array invalid.
     
  • Resize: Creates an empty writable data object. An old BSTR is freed, if it was owned. See the (3)Data constructor for ownership and parameter descriptions.
  • operator=: See the (4)Data copy constructor.

Accessors

  • GetWritablePtr: Returns a writable pointer or NULL, if the object is unwritable. Calling Resize or passing the object as a parameter assignment or copy construction will invalidate the pointer returned here.
  • GetPtr: Returns a pointer to the data array.
  • GetSize: Number of bytes in the array.

Remarks

This class describes an object for fast and efficient data manipulations.

* Rules for Applying and Transferring Ownerships

The internal data representation might be owned by the Data object or not. Various rules apply in regard to managing, manipulating, and transferring this ownership.

Rule 1. Ownership always implies that the Data object has an internal BSTR pointer and that it owns the BSTR. This is the case if you either use the (1)Data constructor with owner=true, or (3)Data, or [Data]Resize with size!=0. When the Data objects goes out of scope it frees the BSTR.
Copy constructor and assignment operator behavior: The ownership is transfered to the other class.

BSTR bs = SysAllocStringByteLen("123", 4);
Data data1(bs);     // data1 owns the BSTR
Data data2(data1);  // data2 now owns the BSTR

{
  Data data3 = data2;  // data3 now owns the BSTR
  // Here data3 goes out of scope.
  // Because it is the owner, it frees the BSTR.
}

data1.GetPtr();     // wrong; the memory was freed by data3's destructor
data2.GetPtr();     // wrong; the memory was freed by data3's destructor

Rule 2. A Data object might store a BSTR pointer, but doesn't own the BSTR nor does its destructor free it. This is the case if you use the (1)Data constructor with owner=false.
Copy constructor and assignment operator behavior: None of the resulting data objects ever receives ownership for the initial BSTR. Rather it is your responsibility to free it.

BSTR bs = SysAllocStringByteLen("123", 4);

Data data1(bs, false);  // owner=false
Data data2(data1);      // owner=false
Data data3 = data2;     // owner=false

// bs must be freed manually as neither data1, data2, nor data3 owns it.
SysFreeString(bs);

Rule 3. A Data object has no BSTR pointer at all. This is the case if you use the (2)Data constructor.
Copy constructor and assignment operator behavior: If such an object is passed to another Data object, internally a BSTR with ownership is created by the other object. This is the only case that implies memory copy operations when using a copy constructor (or an assignment operator). In all other cases just pointers and ownerships are passed around.

unsigned char* ptr = (unsigned char*)"123";

Data data1(ptr, 4);  // owner=false
Data data2(data1);   // data2 allocates its own BSTR (owner=true)
Data data3 = data1;  // data3 allocates its own BSTR unrelated to data2 (owner=true)

// For assignments of data2 and data3 to other objects "Rule 1" applies

Example - Using a Writable Pointer

Data data(4);  // owner=true

unsigned char* ptrSrc = (unsigned char*)"123";
unsigned char* ptrDest = data.GetWritablePtr();

if (ptrDest)
  CopyMemory(ptrDest, ptrSrc, 4);