-
Notifications
You must be signed in to change notification settings - Fork 57
Cpp usage
The Wiselib is written in C++, thereby excessively using templates. It runs on many target platforms, from the tiny MSP430 up to ordinary PCs. However, the support for so many platforms comes with a certain price. There are many GCC versions around, for instance 3.2.3 for the msp430-g++, or the much newer version 4.4 on PCs. For some platforms (MSP and Atmel), there is even no C++ compiler available and it must be compiled by the developer. In such a case, there is no libstdc++.a available, and thus no C++ standard headers and no STL. Furthermore, the Wiselib may run on systems that do not provide dynamic memory allocation (ScatterWeb firmware, Contiki and TinyOs without appropriate modules).
These restrictions must be considered when developing platform independent algorithms in the Wiselib, and are discussed in the following in detail.
It is not allowed to use dynamic memory allocation, hence the keywords malloc
, free
, new
, and delete
are forbidden within any Wiselib algorithm.
Since some compilers do not provide the libstdc++.a, also the C++ standard headers are not allowed to be used. They must be replaced by the corresponding C headers. Example:
// ---------------------------------------------------------------------- // ------------------------------ DO ------------------------------------ // ---------------------------------------------------------------------- #include <math.h> #include <limits.h> // ---------------------------------------------------------------------- // ------------------------------ DONT! --------------------------------- // ---------------------------------------------------------------------- #include <cmath> #include <climits>
As with the standard headers, there is also no STL available. Whenever an algorithm requires a data structure, it should expect this as a template parameter. That way, a user can pass the best-fitting data structure on compilation (e.g., a std::list from the STL where it is available, but a static list from the pSTL on other platforms). If it is not passed via a template parameter, the least common denominator should be used internally: a data structure form the pSTL.
// ---------------------------------------------------------------------- // ------------------------------ DO ------------------------------------ // ---------------------------------------------------------------------- template <typename DS> class MyAlgorithm { ... // common approach: template parameter DS data_structure_; // in case of need: direct use of pSTL static_list<Os, node_id_t> my_list_; } // ---------------------------------------------------------------------- // ------------------------------ DONT! --------------------------------- // ---------------------------------------------------------------------- #include <list> template <...> class MyAlgorithm { ... std::list<node_id_t> my_list_; }
Due to the lack of the libstdc++.a, and not less importantly the overhead in code size, we do not use RTTI in Wiselib algorithms. At least for some platforms, the compiler argument -fno-rtti
is added. Hence, it is not possible to safely do a dynamic_cast
.
As with RTTI, it is also not allowed to use exceptions. The libstdc++.a is not available on all platforms, and it would cause too much overhead. We also compile with -fno-exceptions
for some platforms.
We do not use virtual inheritance in the generic part of the Wiselib. This is for several reasons:
- Slight overhead in code space - one pointer per virtual function (in vtable)
- Slight overhead in performance - one level of indirection per virtual function call
- Most importantly: inability of the compiler to inline virtual functions; this would essentially be a problem in the external interface, where most functions are one-liners
However, for callback functionality, we offer the more powerful approach of delegates (which has also the advantage that one class can register multiple functions at the same caller):
// ---------------------------------------------------------------------- // ------------------------------ DO ------------------------------------ // ---------------------------------------------------------------------- template <...> class MyAlgorithm { public: typedef delegate1<void, void> MyDelegate; template<class T, void (T::*TMethod)(void)> void register_callback(T *obj_pnt ) { del_ = MyDelegate::template from_method<T, TMethod>( obj_pnt ); } void do_callback() { if (del_) del_(); } MyDelegate del_; }; class WannaRegisterCallback { public: void init() { my_alg_.register_callback<WannaRegisterCallback, &WannaRegisterCallback::my_callback>(this); } void my_callback() { /* ... */ } MyAlgorithm<...> my_alg_; }; // ---------------------------------------------------------------------- // ------------------------------ DONT! --------------------------------- // ---------------------------------------------------------------------- class Callback { public: virtual void callback() = 0; }; #include <list> template <...> class MyAlgorithm { public: register_callback( Callback& cb ) { cb_ = &cb } void do_callback() { if (cb_) cb_->callback(); } Callback *cb_; }; class WannaRegisterCallback : public Callback { public: void init() { my_alg_.register_callback(this); } virtual void callback() { /* ... */ } MyAlgorithm<...> my_alg_; }