Sunday, February 05, 2006

wxWidgets Arrays in C++: one more reason to use std::vector<>

In this post I'll talk a little about using std::vector<>.

wxWidgets offers WX_DEFINE_OBJARRAY and other #defines to help you implement vectors (arrays) of your own types. If you are still using this feature, here is another reason to switch to std::vector<>

Intellisense 2005 will not work with wxArrays of your own type. Classes that use them will not be recognized in most cases. The reason is the need to include arrayimp.cpp multiple times. The wxWidgets documentation briefly mentions std::vector but goes on saying that the wxArray mechanism can be compiled with any dumb C++ compiler in the world. (http://www.wxwidgets.org/manuals/2.6.2/wx_wxarray.html)

Well most C++ compilers by now either come with the C++ Standard Template Library included or you can use STLport, a free port of the STL, with your compiler. Almost all compilers now support templates.

So here is my full list of reasons to throw away all WX_ARRAY_DECLARE macros and use std::vector<> instead.

1. std::vector<> works fine with Intellisense, wxArray does not
2. std::vector<> is in the official C++ standard, wxArray is not
3. wxWidgets has a wxUSE_STL switch already and uses STL internally. I expect that future versions will eventually deprecate the WX_ARRAY... macro mechanism.
4. Learing std::vector<> is a great way to get started with the STL, which includes many other, extremely helpful constructs.
5. And after STL: boost. If you haven't heard about it, check it out at www.boost.org. Boost is like a supercharged Standard Template Library. Many more utilities, some easy, others difficult to learn, but once you get the hang of it, they will amaze you.

Here is a quick starter on how to use std::vector<> for objects of type MyDirectory.

struct MyDirectory {
// include some reasonable definition
};


#include <vector>// note: vector, not vector.h

// now define a 'MyDirectory' array
typedef std::vector ArrayOfDirectories;

ArrayOfDirectories m_my_array;

You can now use

// to append a new element to the array
m_my_array.push_back(aDirectory);

// to access an element
m_my_array[5];

// or with boundary check: will throw an error if vector.size()<5
m_my_array.at(5);

// to check the size of the array
m_my_array.size();

// to iterate over array
for (size_t i=0; i<m_my_array.size(); ++i)
do_something(m_my_array[i]);

// to sort the array
sort(m_my_array.begin(), m_my_array.end());

// to find something in the array
find(m_my_array.begin(), m_my_array.end(), value);

// to clear the array
m_my_array.clear();

I prefer vector and other containers (list, map, deque, queue etc...) over their wx counterparts.

Instead of using WX_DECLARE_OBJARRAY(ElementType, Name), write
typedef std::vector Name;

#include arrayimpl and WX_DEFINE_ARRAY are no longer neccessary.

Note that STL lacks WX_SORTED_ARRAY, but you can use std::set for that instead.

Have fun

Hajo

2 comments:

Rick Sivernell said...

You show the following in using stl vectors:
// now define a 'MyDirectory' array
typedef std::vector ArrayOfDirectories;

ArrayOfDirectories m_my_array;


In Unix/Linux all you need is:
// now define as
vector(string) rayOfDirectories;

Why is this not used in M$ Windows using VS 2005?

Anonymous said...

Nowadays you can use wxVector. Still undocumented in wx2.8.x, but documented in wxWidgets 2.9.x (svn 3.0 trunk). Works like std::vector.