Complex smobs are created by deriving from Smob<Classname>.
+ However, this is not sufficient when classes with their own
+ protectable elements are derived from the Complex base class. This
+ is because initialization order is a tricky thing: once a base class
+ calls smobify_self () in its constructor, further allocations during
+ construction of base class and derived classes might lead to
+ mark_smob calls on the object under construction. When those call a
+ virtual function like derived_mark, the virtual function
+ corresponding to the incompletely initialized object of derived
+ class type is likely to be called.
+
+ The order of initialization of an object consists in calling the
+ constructors of virtual base classes, then of non-virtual base
+ classes, then initializing all data members.
+
+ As a result, the constructor of a derived class comes too late for
+ initialization of data members that may be accessed in the
+ derived_mark kind of functions.
+
+ Such data members are consequently moved into Preinit_* classes
+ which come before the smobifying base class in derivation order and
+ construct the contained data members in a state suitable for
+ derived_mark calls.
+
+
CALLING INTERFACE
Common global functions for accessing C++ smob objects:
debugging purposes. If the class does not define this function,
the output will be #<Classname> when printing.
- - a static const type_p_name_[] std::string set to something like
+ - a static const * const type_p_name_ string set to something like
"ly:grob?". When provided, an accordingly named function for
checking for the given smob type will be available in Scheme.
static scm_t_bits smob_tag_;
static Scm_init scm_init_;
static void init (void);
- static std::string smob_name_;
+ static string smob_name_;
protected:
static Super *unchecked_unsmob (SCM s)
{
// Most default functions are do-nothings. void init() will
// recognize their address when not overriden and will then refrain
// altogether from passing the the respective callbacks to GUILE.
+
SCM mark_smob (void) const;
static SCM mark_trampoline (SCM); // Used for calling mark_smob
static size_t free_smob (SCM obj);
static int print_trampoline (SCM, SCM, scm_print_state *);
static void smob_proc_init (scm_t_bits) { };
- // type_p_name_ can be overriden in the Super class with a static
- // const char [] std::string. This requires both a declaration in the
- // class as well as a single instantiation outside. Using a
- // template specialization for supplying a different std::string name
- // right in Smob_base<Super> itself seems tempting, but the C++
- // rules would then require a specialization declaration at the
- // class definition site as well as a specialization instantiation
- // in a single compilation unit. That requires just as much source
- // code maintenance while being harder to understand and quite
- // trickier in its failure symptoms when things go wrong. So we
- // just use a static zero as "not here" indication.
- static const int type_p_name_ = 0;
+ // Define type_p_name_ in the Super class as a const char * const.
+ // Without such definition it defaults to 0, producing no predicate.
+
+ static const char * const type_p_name_; // = 0
// LY_DECLARE_SMOB_PROC is used in the Super class definition for
// making a smob callable like a function. Its first argument is a
extern bool parsed_objects_should_be_dead;
class parsed_dead
{
- static std::vector<parsed_dead *> elements;
+ static vector<parsed_dead *> elements;
SCM data;
SCM readout_one ()
{