Update documentation after setting wxUSE_STD_CONTAINERS=1

Explain that the legacy container classes now inherit from the standard
classes by default and also how to update the existing code to compile
when using standard library-based implementations.
This commit is contained in:
Vadim Zeitlin 2023-04-10 19:18:06 +01:00
parent 3335be1362
commit 89e4f51f62
7 changed files with 137 additions and 113 deletions

View file

@ -87,6 +87,11 @@ Changes in behaviour which may result in build errors
- Building with wxUSE_UNICODE=0 is not supported any longer.
- wxUSE_STD_CONTAINERS is now set to 1 by default, see "Container Classes"
overview in the manual for the description of the changes this may require in
the existing code. Alternatively, explicitly set wxUSE_STD_CONTAINERS=0 when
compiling the library to preserve full compatibility with the old versions.
- wxMotif and wxGTK1 ports have been removed, please use wxWidgets 3.2 if you
still need them.

View file

@ -14,34 +14,30 @@
For historical reasons, wxWidgets uses custom container classes internally.
This was unfortunately unavoidable during a long time when the standard library
wasn't widely available and can't be easily changed even now that it is for
compatibility reasons. If you are building your own version of the library and
don't care about compatibility nor slight (less than 5%) size penalty imposed
by the use of STL classes, you may choose to use the "STL" build of wxWidgets
in which these custom classes are replaced with their standard counterparts and
only read the section @ref overview_container_std explaining how to do it.
compatibility reasons. However, starting from version 3.3.0 these custom
container classes are implemented in terms of the standard library classes by
default and so are mostly interoperable with them.
Otherwise you will need to know about the custom wxWidgets container classes
such as wxList<T> and wxArray<T> if only to use wxWidgets functions that work
with them, e.g. wxWindow::GetChildren(), and you should find the information
about using these classes below useful.
This means that even if some wxWidgets function is documented as taking or
returning a legacy container such as wxList<T> or wxArray<T>, you can work with
them as if they were just `std::list<T*>` or `std::vector<T>`. For example,
wxWidgets::GetChildren() is documented as returning a `wxWindowList`, which
inherits from `std::list<wxWindow*>` and so can be used as such, e.g.
Notice that we recommend that you use standard classes directly in your own
code instead of the container classes provided by wxWidgets in any case as the
standard classes are easier to use and may also be safer because of extra
run-time checks they may perform as well as more efficient.
@code
const auto& children = someFrame->GetChildren();
auto it = std::find(children.begin(), children.end(), someWindow);
if ( it != children.end() )
// ... do something with this window ...
@endcode
Finally notice that recent versions of wxWidgets also provide standard-like
classes such as wxVector<T>, wxStack<T> or wxDList which can be used exactly
like the std::vector<T>, std::stack<T> and std::list<T*>, respectively, and
actually are just typedefs for the corresponding types if wxWidgets is compiled
in STL mode. These classes could be useful if you wish to avoid the use of the
standard library in your code for some reason.
To summarize, you should use the standard container classes such as
std::vector<T> and std::list<T> if possible and wxVector<T> or wxDList<T> if
it isn't and only use legacy wxWidgets containers such as wxArray<T> and
wxList<T> when you must, i.e. when you use a wxWidgets function taking or
returning a container of such type.
You may still need to create wxWidgets containers to pass them to some
wxWidgets function, e.g. wxDir::GetAllFiles() requires a wxArrayString to be
passed in. However in this case you may still the object as if it were just a
`std::vector<wxString>` and, other than that, there is no reason to use the
container classes provided by wxWidgets anywhere in the new code, they only
exist for backwards compatibility and standard library classes should be used
by the application.
@see @ref group_class_containers
@ -49,81 +45,95 @@ returning a container of such type.
@section overview_container_legacy Legacy Classes
The list classes in wxWidgets are doubly-linked lists which may either own the
objects they contain (meaning that the list deletes the object when it is
removed from the list or the list itself is destroyed) or just store the
pointers depending on whether or not you called wxList<T>::DeleteContents()
method.
This section contains a brief overview of the legacy container classes and is
mostly useful if you need to maintain an existing code base using them -- none
of this is really necessary to know if you follow the advice above and treat
all wxWidgets containers as if they were standard containers.
Dynamic arrays resemble C arrays but with two important differences: they
provide run-time range checking in debug builds and they automatically expand
the allocated memory when there is no more space for new items. They come in
two sorts: the "plain" arrays which store either built-in types such as "char",
"int" or "bool" or the pointers to arbitrary objects, or "object arrays" which
own the object pointers to which they store.
For the same portability reasons, the container classes implementation in
wxWidgets don't use templates, but are rather based on C preprocessor i.e. are
implemented using the macros: WX_DECLARE_LIST() and WX_DEFINE_LIST() for the
linked lists and WX_DECLARE_ARRAY(), WX_DECLARE_OBJARRAY() and
WX_DEFINE_OBJARRAY() for the dynamic arrays.
All these classes use macro-based machinery to define type-safe classes based
on the generic implementation. Generally speaking, this consists of using one
macro to declare a particular "instantiation" and then another one to actually
define it, e.g. WX_DECLARE_LIST() and WX_DEFINE_LIST() for the linked lists or
WX_DECLARE_OBJARRAY() and WX_DEFINE_OBJARRAY() for the arrays containing
objects. The array classes storing primitive types, such as `int`, don't need
to be declared and defined separately, and so only WX_DEFINE_ARRAY_INT()
exists, without the matching "DECLARE" macro.
The "DECLARE" macro declares a new container class containing the elements of
given type and is needed for all three types of container classes: lists,
arrays and objarrays. The "DEFINE" classes must be inserted in your program in
a place where the @e full declaration of container element class is in scope
(i.e. not just forward declaration), otherwise destructors of the container
elements will not be called!
As array classes never delete the items they contain anyhow, there is no
WX_DEFINE_ARRAY() macro for them.
Examples of usage of these macros may be found in wxList<T> and wxArray<T>
documentation.
given type and can be used in a header file and don't require the full
declaration of the contained type. The "DEFINE" macros must be used in a place
where the @e full declaration of container element class is in scope (i.e. not
just forward declaration).
Finally, wxWidgets predefines several commonly used container classes. wxList
is defined for compatibility with previous versions as a list containing
wxObjects and wxStringList as a list of C-style strings (char *), both of these
classes are deprecated and should not be used in new programs. The following
array classes are defined: wxArrayInt, wxArrayLong, wxArrayPtrVoid and
wxArrayString. The first three store elements of corresponding types, but
wxArrayString is somewhat special: it is an optimized version of wxArray which
uses its knowledge about wxString reference counting schema.
itself is defined for compatibility with very old versions of wxWidgets as a
list containing wxObjects and wxStringList as a list of C-style strings
(`char *`). There are also a few predefined array classes including wxArrayInt,
wxArrayLong, wxArrayPtrVoid and wxArrayString, similar to `std::vector`
instantiations for `int`, `long`, `void*` and `wxString` respectively.
@section overview_container_std STL Build
@section overview_container_impls Different Implementations
To build wxWidgets with the standard containers you need to set
wxUSE_STD_CONTAINERS option to 1 in @c wx/msw/setup.h for wxMSW builds or
specify @c \--enable-std_containers option to configure (which is also
implicitly enabled by @c \--enable-stl option) in Unix builds.
Since wxWidgets 3.3.0, all legacy container classes are implemented in terms of
the standard library classes. These implementations are mostly, but not
completely, compatible with the implementation provided by wxWidgets itself
which was used by default in the previous versions.
The standard container build is mostly, but not quite, compatible with the
default one. Here are the most important differences:
- wxList::compatibility_iterator must be used instead of wxList::Node* when
iterating over the list contents. The compatibility_iterator class has the
same semantics as a Node pointer but it is an object and not a pointer, so
you need to write
If the existing code doesn't compile with the implementation based on the
standard containers, it's possible to rebuild the library to use the legacy
implementation of them by setting wxUSE_STD_CONTAINERS option to 0. This is
done by:
- Either manually editing `wx/msw/setup.h` file to change the option of this
value there for wxMSW.
- Or using `--disable-std_containers` option when calling configure when
building wxWidgets under Unix-like systems.
- Or using `-DwxUSE_STD_CONTAINERS=OFF` when using CMake build system.
However a better approach is to update the legacy code to work with the new
container classes implementation. In most cases this can be done in such a way
that they still continue to work with the legacy implementation as well, thus
allowing the application to compile with the default configurations of both
wxWidgets 3.3 and 3.2 and even earlier versions.
Here are some modifications that may need to be done in order to make the
existing compatible with the default build of wxWidgets 3.3:
- `wxList::compatibility_iterator` must be used instead of `wxList::Node*` when
iterating over the list contents. The `compatibility_iterator` class has the
same semantics as a `Node` pointer but it is an object and not a pointer, so
the old code doing
@code
for ( wxWindowList::Node *n = list.GetFirst(); n; n = n->GetNext() ) {
// ... do something with *n ...
}
@endcode
can be mechanically rewritten as
@code
for ( wxWindowList::compatibility_iterator it = list.GetFirst();
it;
it = it->GetNext() )
...
it = it->GetNext() ) {
// ... do something with *it ...
}
@endcode
instead of the old
Of course, if compatibility with the previous wxWidgets versions is not
important, an even better and simpler way to rewrite it is
@code
for ( wxWindowList::Node *n = list.GetFirst(); n; n = n->GetNext() )
...
for ( const auto& elem: list ) {
// ... do something with elem ...
}
@endcode
- wxSortedArrayString and wxArrayString are separate classes now and the
former doesn't derive from the latter. If you need to convert a sorted array
to a normal one, you must copy all the elements. Alternatively, you may
avoid the use of wxSortedArrayString by using a normal array and calling its
Sort() method when needed.
- WX_DEFINE_ARRAY_INT(bool) cannot be used because of the differences in
std::vector<bool> specialization compared with the generic std::vector<>
class. Please either use std::vector<bool> directly or use an integer array
wxArrayString::Sort() method when needed.
- `WX_DEFINE_ARRAY_INT(bool)` cannot be used because of the differences in
`std::vector<bool>` specialization compared with the generic std::vector<>
class. Please either use `std::vector<bool>` directly or use wxArrayInt
instead.
*/

View file

@ -10,7 +10,8 @@
wxArrayString is a legacy class similar to std::vector<wxString>.
This class shouldn't normally be used in the new code, but is still needed
As all the other legacy @ref overview_container "container classes",
this class shouldn't normally be used in the new code, but is still needed
when passing multiple items to various functions in wxWidgets API, notably
the constructors of various GUI control classes. Usually, even in this case
it doesn't need to be used explicitly, as wxArrayString will be implicitly
@ -123,8 +124,10 @@ public:
/**
Constructs the container with the contents of the vector @a vec.
When using @ref overview_container_std, this constructor is more
efficient than the overload taking const reference to the vector.
In the default build, in which wxArrayString is implemented using
`std::vector<>` internally, this constructor is more efficient than the
overload taking const reference to the vector, as it reuses the
existing vector data instead of copying it.
Otherwise it is identical to the other overload, see its documentation
for more details.
@ -158,17 +161,18 @@ public:
/**
Constructs a std::vector containing the same strings as this array.
In @ref overview_container_std, this function actually returns a const
reference to this object itself, without making a copy, but in the
default/compatible build, it has to copy all the strings, making it
expensive to call for big arrays.
In the default build configuration, this function returns a const
reference to this object itself, without making a copy. But when using
the legacy implementation of wxArrayString not based on `std::vector`,
it has to copy all the strings, making it expensive to call for big
arrays.
Note that using it like this:
@code
const std::vector<wxString>& vec = array.AsVector();
@endcode
works in all builds as long as you don't need to modify the returned
vector and doesn't impose any extra overhead in the STL build.
works in all build variants as long as you don't need to modify the
returned vector and doesn't impose any extra overhead.
@since 3.3.0
*/

View file

@ -9,6 +9,9 @@
The legacy dynamic array class, existing for compatibility only and @e NOT
to be used in the new code.
@note Please see @ref overview_container for more information about legacy
container classes in wxWidgets.
This section describes the so called @e "dynamic arrays". This is a C
array-like type safe data structure i.e. the member access time is constant
(and not linear according to the number of container elements as for linked

View file

@ -6,12 +6,14 @@
/////////////////////////////////////////////////////////////////////////////
/**
@class wxHashMap
wxHashMap is a legacy hash table container similar to std::unordered_map.
This is a simple, type-safe, and reasonably efficient hash map class,
whose interface is a subset of the interface of STL containers.
In particular, the interface is modelled after std::map, and the various,
non-standard, std::hash_map (http://www.cppreference.com/wiki/stl/map/start).
@note As all the other legacy @ref overview_container "container classes",
this class shouldn't be used in the new code.
Please see https://en.cppreference.com/w/cpp/container/unordered_map for
the full description of this class API: in the default build, this class is
a thin wrapper inheriting from the standard class.
Example:
@code

View file

@ -6,13 +6,14 @@
/////////////////////////////////////////////////////////////////////////////
/**
@class wxHashSet
wxHashSet is a legacy hash set container similar to std::unordered_set.
This is a simple, type-safe, and reasonably efficient hash set class,
whose interface is a subset of the interface of STL containers.
@note As all the other legacy @ref overview_container "container classes",
this class shouldn't be used in the new code.
The interface is similar to std::tr1::hash_set or std::set classes but
notice that, unlike std::set, the contents of a hash set is not sorted.
Please see https://en.cppreference.com/w/cpp/container/unordered_set for
the full description of this class API: in the default build, this class is
a thin wrapper inheriting from the standard class.
Example:
@code

View file

@ -6,17 +6,20 @@
/////////////////////////////////////////////////////////////////////////////
/**
The wxList<T> class provides linked list functionality.
wxList<T> is a legacy class similar to std::list<T*>.
This class has been rewritten to be type safe and to provide the full API of
the STL std::list container and should be used like it if you use it at
all, which is not recommended in the new code.
@note As all the other legacy @ref overview_container "container classes",
this class shouldn't be used in the new code.
The exception is that wxList<T> actually stores pointers and therefore its
iterators return pointers and not references to the actual objects in the list
(see example below) and @e value_type is defined as @e T*.
wxList<T> destroys an object after removing it only if wxList<T>::DeleteContents
has been called.
This class is similar to the other container classes in that it provides
all the usual functions of its standard library counterpart, `std::list`.
However, unlike the other classes, this class always stores pointers to the
objects and not the objects themselves, i.e. its @e value_type is defined
as @e T*.
Moreover, wxList<T> only destroys an object after removing it if
wxList<T>::DeleteContents has been called, i.e. it does _not_ manage its
items memory by default.
wxList<T> is not a real template and it requires that you declare and define
each wxList<T> class in your program. This is done with @e WX_DECLARE_LIST
@ -24,16 +27,12 @@
provide a proper template class providing both the STL @c std::list and the old
wxList API in the future.
Please refer to the STL @c std::list documentation (see http://www.cppreference.com/wiki/stl/list/start)
Please refer to the STL @c std::list documentation (see https://en.cppreference.com/w/cpp/container/list)
for further information on how to use the class.
Below we documented both the supported STL and the legacy API
that originated from the old wxList class and which can still be used alternatively
for the same class.
Note that if you use @ref overview_container_std of wxWidgets,
then wxList<T> will actually derive from @c std::list and just add a legacy
compatibility layer for the old wxList class.
@code
// this part might be in a header or source (.cpp) file
class MyListElement