The following are rewrite of my 20-years old coding guide lines. I'd like to
ask for suggestions to refine in the way because one reason is that recently
the many questions I saw in this forum are actually rooted in class design
problems (or problems of being too expressive, arbitrary).
------
I think one major feature C++ provides is the support (or restriction) of
Object-oriented Design. From the wiki
https://en.wikipedia.org/wiki/Object-oriented_design
or others, the definition is a bit difficult to be practically applicable. And
the 'isa' part ideal of OOD I knew didn't properly work.
In addition, C++ class actually works by 'semantics' (or convention) which is
not mentioned anywhere (E.g. default constructor,copy constructor and operator=).
Thus, the following guide lines are defined (exceptions are few):
Constructor(..):
Constructor forms are in basic the Cartesian product view of problem domain
in tupple. IOW, the arguments of ctors define the class (concept).
Constructor brings an object in random state to responsible state.
Destructor:
The destructed object is no longer considered existing in the C++ language
(ref. [12.4.14]). Since destructing an object the second time results to
undefined behavior, destructor must make sure destructing it once is enough.
In another word, destructor must succeed to the language. Object destruction
actually magnifies the effect of common ignorance of the implicitly created
rollback function (or a design).... The program execution from return/throw/
exit.. to its caller(e.g. main, init..) shall succeed.
const member functions:
Const members describe the property of the class. Normally, these members
should be in O(1) complexity. And, if properties of two objects are equal,
the objects should behave the same.
Reset(..) members:
Reset members brings the object from responsible state back to random state
and then does whatever the argument corresponding constructor does.
Therefore, If a reset member exists then the argument(s) corresponding
constructor also exists.
Construct/destruct/reset are implemented as composite operations of object
initialization process of the life cycle view (and the symmetrical reverse).
Implementation can optimize the theoretical sequence.
Since this library adopts an implicit rule that object has to be in a 'valid'
state (no good in class Array), the reset() postcondition is thus required to
be default. Default state is among the easiest check points to ensure object
constructed, in whatever valid state it may be, can always be successfully
destructed. Note that reset members normally exist but not necessary. For
instance, if the class contains const or reference data members, then the
reset would be difficult to implement.
Move Constructor:
The motivation of devising is from the need to avoid costly and unnecessary
copy operations found in classes that contain allocated resources and the
objects movement in a dynamic array. It has been practiced that such
motivation basically just need a *move constructor*. This library uses
"enum ByMove_t { ByMove }" as the signature denoting a move constructor (for
the moment), which is defined to move the source referenced object to 'this'
pointed address (source object is treated non-existent). The reason is that
such an operation is conceptually elementary, thus can enable the definition
of a no-throw swap function template (note: implementation needs a buffer
type, e.g. type_store<T>, but this is a different issue).
Many other libraries do not contain the move constructor. Bit-wise copy
(memcpy) may mostly do the job, e.g. QString of Qt library, so far. Just
make sure that destructor of the moved object won't be called.
Note: C++11 introduced rv-reference and defined another name 'std::move',
a constructor taking a rv-reference argument is therefore called a move
constructor. This library decided to continue the development using this now
standard-confusing move constructor. Simply because ByMove is relatively
more elementary. Many reasons can eventually be translated to being light
weight, which in a way means it can transform easier. Again, This library's
guide "No room should be left for lower-level implement". Another reason is
the ratio of gain v.s. cost does not appear good for the author to use it,
hopefully this library can survive.
-------- Class member rules
Let T denote a given class of this library. The following member names
and associated functionality are defined.
T() Default constructor. The object thus construted is referred
to as in default state and so the default object.
Postcondition of throw: object does not exist.
Note: If object can mean 'no real contents', the default object is
better thus designed, at least to be safely destructable.
Errno reset(...)
Reconstruct the object to the state as constructed.
If reset(..) defined, there exists the argument corresponding
constructor (reset() usually exists)
Ex: reset members should function identical to the following
example:
Errno T::reset(Type1 a, Type2 b) try {
T obj(a,b);
swap(*this,obj);
return Ok;
}
catch(const Errno& e) {
return e;
};
Note: This rule is important. Real practice may want do things
slightly different in some cases, but no, hidden, hard to find
bugs may exist.
Note: For reset() (no argument), object return state (and Reply) is
always default.
~T Destruct object
Postcondition: object does not exist
bool is_default() const
return true iff object is equivalent to the default constructed
object (i.e a.is_default() <==> a==T(), if operator== is defined).
bool operator==(const T& rhs) const
This function returns true iff *this and rhs are not
distinguishable by using any non-private member on the same
condition unless otherwise explicitly specified.
Note: Object equivalence does not include equivalence of SLI and
address of its own.
T& operator=(const T&)
Reconstruct object to the state as the copy constructor constructed
(same as reset(const T&) except the return type and throwing error).
void swap(&T)
Exchange object state of *this and the argument indicated object.
Take 'a.swap(b)' (commutative) for instance, the state of a is set
to the state of b. The previous state of a becomes the state of b.
The same applies for b
Note: No construct and destruct semantics involved
Reply
Class specific throw class inherited from Wy::Errno.
_.. prefix for system-specific members or candidate, or restricted
wy_.. prefix for internal members (for test codes, etc.).
------