Cross-Platform GUI Programming with wxWidgets

wxWidgets provides a dynamic array structure using wxArray, similar to C arrays in that the member access time is constant. However, these arrays are dynamic in the sense that they will automatically allocate more memory if there is not enough of it for adding a new element. Adding items to the arrays is also implemented in more or less constant timebut the price is pre-allocating the memory in advance. wxArray also provides range checking, asserting in debug builds or silently returning in release builds (though your program might get an unexpected value from array operations).

Array Types

wxWidgets has three different kinds of arrays. All derive from wxBaseArray, which works with untyped data and cannot be used directly. The macros WX_DEFINE_ARRAY, WX_DEFINE_SORTED_ARRAY, and WX_DEFINE_OBJARRAY are used to define a new class deriving from it. The classes are referred to as wxArray, wxSortedArray, and wxObjArray, but you should keep in mind that no classes with such names actually exist.

wxArray is suitable for storing integer types and pointers, which it does not treat as objects in any waythat is, the element referred to by the pointer is not deleted when the element is removed from the array. It should be noted that all of wxArray's functions are inline, so it costs nothing to define as many array types as you want (either in terms of the executable size or speed). This class has one serious limitation: it can only be used for storing integral types (bool, char, short, int, long, and their unsigned variants) or pointers (of any kind). Data of type float or double should not be stored in a wxArray.

wxSortedArray is a wxArray variant that should be used when you will be searching the array frequently. wxSortedArray requires you to define an additional function for comparing two elements of the array element type and always stores its items in the sorted order (according to the sort function). Assuming that you search the array far less frequently than you add to it, wxSortedArray may lead to huge performance improvements compared to wxArray. It should be noted that wxSortedArray shares wxArray's type restriction and should only be used for storing integral types or pointers.

wxObjArray class treats its elements like objects. It can delete them when they are removed from the array (invoking the correct destructor), and it copies them using the object's copy constructor. The definition of the wxObjArray arrays is split into two parts. First, you should declare the new wxObjArray class using the WX_DECLARE_OBJARRAY macro. Second, you must include the file defining the implementation of template type <wx/arrimpl.cpp> and define the array class with the WX_DEFINE_OBJARRAY macro from a point where the full declaration of the array elements class is in scope. This technique will be demonstrated in the array sample code presented later in this chapter.

wxArrayString

wxArrayString is an efficient container for storing wxString objects and has the same features as the other wxArray classes. It is also very compact and doesn't take more space than a C array wxString[] type (wxArrayString uses its knowledge of internals of wxString class to achieve this). All of the methods available in the other wxArray types are also available in wxArrayString.

This class is used in the same way as other dynamic arrays, except that no WX_DEFINE_ARRAY declaration is needed for ityou can use wxArrayString directly. When a string is added or inserted in the array, a copy of the string is created, so the original string may be safely deleted. In general, there is no need to worry about string memory management when using this classit will always free the memory it uses.

The references returned by Item, Last, or operator[] are not constant, so the array elements may be modified in place:

array.Last().MakeUpper();

There is also a variant of wxArrayString called wxSortedArrayString that has exactly the same methods as wxArrayString, but always keeps its strings in alphabetical order. wxSortedArrayString uses binary search in its Index, which makes it much more efficient if you rarely add strings to the array but search for them often. The Insert and Sort methods should not be used with wxSortedArrayString because they are likely to break the order of items.

Array Construction, Destruction, and Memory Management

Array classes are C++ objects and as such have the appropriate copy constructors and assignment operators. Copying a wxArray copies the elements, but copying a wxObjArray copies the array's items. However, for the sake of memory efficiency, neither of these classes has a virtual destructor. It is not very important for wxArray, which has a trivial destructor, but it does mean that you should avoid deleting wxObjArray through a wxBaseArray pointer and that you should not derive your own classes from the array classes.

Automatic array memory management is quite trivial: the array starts by pre-allocating some minimal amount of memory (defined by WX_ARRAY_DEFAULT_INITIAL_SIZE). When further new items exhaust previously allocated memory, the array reallocates itself, adding 50% of the currently allocated amount, but no more than ARRAY_MAXSIZE_INCREMENT. The Shrink method deallocates any extra memory. The Alloc method can be quite useful if you know in advance how many items you are going to put in the array, and using it will prevent the array code from reallocating the memory more often than needed.

Array Sample Code

The array sample presented here shows the most complex case, using a wxObjArray to store custom objects. Using a wxArray for primitive types or pointers would work identically in terms of syntax and semantics, but the wxArray would never take ownership of the objects.

// Our data class to store in the array class Customer { public: int CustID; wxString CustName; }; // this part might be in a header or source (.cpp) file // declare our array class: // this macro declares and partly implements CustomerArray class // (which derives from wxArrayBase) WX_DECLARE_OBJARRAY(Customer, CustomerArray); // the only requirement for the rest is to be AFTER the full // declaration of Customer (for WX_DECLARE_OBJARRAY forward // declaration is enough), but usually it will be found in the // source file and not in the header #include <wx/arrimpl.cpp> WX_DEFINE_OBJARRAY(CustomerArray); // Used when sorting to compare objects int arraycompare(Customer** arg1, Customer** arg2) { return ((*arg1)->CustID < (*arg2)->CustID); } // Show Array operations void ArrayTest() { // Declare an instance of our array CustomerArray MyArray; bool IsEmpty = MyArray.IsEmpty(); // will be true // Create some customers Customer CustA; CustA.CustID = 10; CustA.CustName = wxT("Bob"); Customer CustB; CustB.CustID = 20; CustB.CustName = wxT("Sally"); Customer* CustC = new Customer(); CustC->CustID = 5; CustC->CustName = wxT("Dmitri"); // Append two customers to the array MyArray.Add(CustA); MyArray.Add(CustB); // Insert last customer into arbitrary place in the array // The array will not own this CustC object, it will own a copy MyArray.Insert(*CustC, (size_t)0); int Count = MyArray.GetCount(); // will be 3 // If not found, wxNOT_FOUND is returned int Index = MyArray.Index(CustB); // will be 2 // Process each customer in the array for (unsigned int i = 0; i < MyArray.GetCount(); i++) { Customer Cust = MyArray[i]; // or MyArray.Item(i); // Process Customer } // Sort the customers according to the sort function MyArray.Sort(arraycompare); // Remove Customer A from the array, but do not delete Customer* pCustA = MyArray.Detach(1); // We must deallocate the object ourself if using Detach delete pCustA; // Remove will also delete the Customer object MyArray.RemoveAt(1); // Clears the array, deleting all objects MyArray.Clear(); // The array never owned this object delete CustC; }

    Категории