TITLE("Moveable")
TOPIC_TEXT(
"[ $$0,0#00000000000000000000000000000000:Default][l288;i704;a17;O9;~~~.992; $$1,"
"0#10431211400427159095818037425705:param][a83;*R6 $$2,5#3131016247420302412518841"
"7583966:caption][b83;* $$3,5#07864147445237544204411237157677:title][b167;a42;C $"
"$4,6#40027414424643823182269349404212:item][b42;a42; $$5,5#4541300047534217475409"
"1244180557:text][l288;a17; $$6,6#27521748481378242620020725143825:desc][l321;t246"
";C@5;1 $$7,7#20902679421464641399138805415013:code][b2503; $$8,0#6514237545610002"
"3862071332075487:separator][*@(0.0.255) $$9,0#83433469410354161042741608181528:ba"
"se][t4167;C+117 $$10,0#37138531426314131251341829483380:class][l288;a17;*1 $$11,1"
"1#70004532496200323422659154056402:requirement][i416;b42;a42;O9;~~~.416; $$12,12#"
"10566046415157235020018451313112:tparam][b167;C $$13,13#9243045944346046191110808"
"0531343:item1][a42;C $$14,14#77422149456609303542238260500223:item2][*@2$(0.128.1"
"28) $$15,15#34511555403152284025741354420178:NewsDate][l321;*C$7 $$16,16#03451589"
"433145915344929335295360:result][l321;b83;a83;*C$7 $$17,17#0753155046352950537122"
"8428965313:result`-line][l160;t4167;*C+117 $$18,5#8860394944220582595880005322242"
"5:package`-title][{_}%EN-US [s2;%00-00 [%00-00 Moveable]&][s5; [%00-00 Moveable] "
"concept represents basic requirement for types stored in Vector flavor of contain"
"ers (namely Vector, [%00-00 BiVector], Index and [%00-00 VectorMap]). To explain "
"what is and why it is so important let us first create very primitive Vector-like"
" container template&][s7;%00-00 [%00-00 template <class T>]&][s7;%00-00 [%00-00 c"
"lass SimpleVector {]&][s7;%00-00 [%00-00 -|T  *vector;]&][s7;%00-00 [%00-00 -|int"
" capacity;]&][s7;%00-00 [%00-00 -|int items;]&][s7;%00-00 &][s7;%00-00 [%00-00 -|"
"void ][%00-00* Expand()][%00-00  {]&][s7;%00-00 [%00-00 -|-|capacity = 2 * capaci"
"ty;]&][s7;%00-00 [%00-00 -|-|T *newvector = (T *) new char`[capacity * sizeof(T)`"
"];]&][s7;%00-00 [%00-00 -|-|for(int i = 0; i < items; i`++) {]&][s7;%00-00 [%00-0"
"0 -|-|-|][%00-00* new(newvector`[i`]) T(vector`[i`])][%00")
TOPIC_TEXT(
"-00 ;]&][s7;%00-00* [%00-00* -|-|-|][%00-00 vector`[i`].T`::~T();]&][s7;%00-00 ["
"%00-00 -|-|}]&][s7;%00-00 [%00-00 -|-|delete`[`] (char *) vector;]&][s7;%00-00 [%"
"00-00 -|-|vector = newvector;]&][s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 publi"
"c:]&][s7;%00-00 [%00-00 -|void Add(const T`& x) {]&][s7;%00-00 [%00-00 -|-|if(ite"
"ms >= capacity) ][%00-00* Expand()][%00-00 ;]&][s7;%00-00 [%00-00 -|-|new(vector`"
"[items`++`]) T(x);]&][s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 -|T`& operator`["
"`](int i) { return vector`[i`]; }]&][s7;%00-00 [%00-00 -|SimpleVector() {]&][s7;%"
"00-00 [%00-00 -|-|vector = NULL;]&][s7;%00-00 [%00-00 -|-|capacity = items = 0;]&"
"][s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 -|~SimpleVector() {]&][s7;%00-00 [%0"
"0-00 -|-|for(int i = 0; i < items; i`++)]&][s7;%00-00 [%00-00 -|-|-|vector`[i`].T"
"`::~T();]&][s7;%00-00 [%00-00 -|-|delete`[`] (char *)vector;]&][s7;%00-00 [%00-00"
" -|}]&][s7; };&][s5; This [%00-00* SimpleVector] stores added elements in [* vect"
"or]. If there is not sufficient space left in [* vector], [%00-00* SimpleVector] "
"simply doubles its capacity using [* Expand] method. And this method is what inte"
"rests us - because [* Expand ]requires means to copy values of elements from the "
"original [* vector] to new allocated one. Above version uses placement new and co"
"py constructor for this purpose. This also means that [%00-00* SimpleVector] requ"
"ires T to have copy constructor (in standard C`++ library terms: it must be [/ co"
"py-constructible]). Now let us create a typical element that can be stored in suc"
"h container&][s7;%00-00 [%00-00 class SimpleString {]&][s7;%00-00 [%00-00 -|char "
"*text;]&][s7;%00-00 [%00-00 public:]&][s7;%00-00 [%00-00 -|SimpleString(const cha"
"r *txt) {]&][s7;%00-00 [%00-00 -|-|text = new char`[strlen(txt)`];]&][s7;%00-00 ["
"%00-00 -|-|strcpy(text, txt);]&][s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 -|Sim"
"pleString(const SimpleString`& s) {]&][s7;%00-00 [%00-00 -|-|text = new char`[str"
"len(s.text)`];]&][s7;%00-00 [%00-00 -|-|strcpy(text, s.te")
TOPIC_TEXT(
"xt);]&][s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 -|void operator=(const Simple"
"String`& s) {]&][s7;%00-00 [%00-00 -|-|delete`[`] text;]&][s7;%00-00 [%00-00 -|-|"
"text = new char`[strlen(s.text)`];]&][s7;%00-00 [%00-00 -|-|strcpy(text, s.text);"
"-|-|]&][s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 -|SimpleString() {]&][s7;%00-0"
"0 [%00-00 -|-|delete`[`] text;]&][s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 };]&"
"][s5; and see what happens when [%00-00* SimpleVector][%00-00  ]of [%00-00* Simpl"
"eString][%00-00 s] is expanded: First, copies of all elements are created, that m"
"eans allocating new storage for [* text] member of new element and copying source"
" [* text] to it using [%00-00* strcpy]. A moment later, [* Expand] invokes destru"
"ctor for element, thus deleting all [* text]s in the original elements. Does not "
"it seem we are wasting a lot of CPU cycles just to make copies of things that we "
"throw away moment later anyway ? What if instead of making copies we could find a"
" way to transfer original element's [* text] members to new one and somehow disal"
"low [* delete`[`] text] in destructor? See how primitive it can be:&][s7;%00-00 ["
"%00-00 template <class T>]&][s7;%00-00 [%00-00 class SimpleVector {]&][s7;%00-00 "
"[%00-00 -|T  *vector;]&][s7;%00-00 [%00-00 -|int capacity;]&][s7;%00-00 [%00-00 -"
"|int items;]&][s7;%00-00 &][s7;%00-00 [%00-00 -|void Expand() {]&][s7;%00-00 [%00"
"-00 -|-|capacity = 2 * capacity;]&][s7;%00-00 [%00-00 -|-|T *newvector = (T *) ne"
"w char`[capacity * sizeof(T)`];]&][s7;%00-00* [%00-00* -|-|][%00-00 memcpy(newvec"
"tor, vector, items * sizeof(T));]&][s7;%00-00 [%00-00 -|-|delete`[`](char *)vecto"
"r;]&][s7;%00-00 [%00-00 -|-|vector = newvector;]&][s7;%00-00 [%00-00 -|}]&][s7;%0"
"0-00 [%00-00 public:]&][s7;%00-00 [%00-00 -|void Add(const T`& x) {]&][s7;%00-00 "
"[%00-00 -|-|if(items >= capacity) Expand();]&][s7;%00-00 [%00-00 -|-|new(vector`["
"items`++`]) T(x);]&][s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 -|SimpleVector() "
"{]&][s7;%00-00 [%00-00 -|-|vector = NULL;]&][s7;%00-00 [%")
TOPIC_TEXT(
"00-00 -|-|capacity = items = 0;]&][s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 -|"
"~SimpleVector() {]&][s7;%00-00 [%00-00 -|-|for(int i = 0; i < items; i`++)]&][s7;"
"%00-00 [%00-00 -|-|-|vector`[i`].T`::~T();]&][s7;%00-00 [%00-00 -|-|delete`[`] (c"
"har *)vector;]&][s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 };]&][s5; For the mom"
"ent please ignore fact that by using [%00-00 memcpy] to move non-POD types we vio"
"late C`++ standard (we will discuss it later). Now, what we get here is exactly w"
"hat we wanted - instead of copy construction and destruction we simply copy raw b"
"inary data to the new location. This way we simply get [* text ]member of element"
"s to new expanded [* vector]. We need to invoke neither copy constructor nor dest"
"ructor when expanding vector. Not a single CPU cycle lost.&][s5;*/ [*/ Types that"
" can be moved in memory using ][%00-00*/ memcpy][*/  we call ]moveable.&][s5; Cle"
"arly not all types are moveable. Certainly, being moveable has a lot to do with s"
"toring references to object itself or to its parts. E.g.&][s7;%00-00 [%00-00 stru"
"ct Link {]&][s7;%00-00 [%00-00 -|Link *prev;]&][s7;%00-00 [%00-00 public:]&][s7;%"
"00-00 [%00-00 -|Link()        { prev = NULL; }]&][s7;%00-00 [%00-00 -|Link(Link *"
"p) { prev = p; }]&][s7;%00-00 [%00-00 };]&][s5;%00-00 [%00-00 is ][%00-00* not][%"
"00-00  moveable, because memcpy-ing to new location would break existing links. W"
"e define these requirements for moveable types:]&][s5;i150;O0; If a type is funda"
"mental, it is moveable.&][s5;i150;O0; Moveable types must not have any virtual me"
"thod nor virtual bases.&][s5;i150;O0; Base classes (if any) and any instance vari"
"ables are moveable.&][s5;i150;O0; No method of moveable object can store directly"
" or indirectly any references to itself, its base subobjects or its instance vari"
"ables to any variable that exists outside the scope of the method (that is, when "
"the method terminates).&][s5; Example:&][s7;%00-00 [%00-00 struct Foo;]&][s7;%00-"
"00 &][s7;%00-00 [%00-00 Foo *global`_foo;]&][s0;%00-00 &]")
TOPIC_TEXT(
"[s7;%00-00 [%00-00 struct Foo {]&][s7;%00-00 [%00-00 -|int a;]&][s7;%00-00 [%00-"
"00 -|Foo *foo;]&][s7;%00-00 [%00-00 -|int *ptr;]&][s7;%00-00 [%00-00 public:]&][s"
"7;%00-00 [%00-00 -|void Set(Foo * f) {]&][s7;%00-00 [%00-00 -|-|foo = f;]&][s7;%0"
"0-00 [%00-00 -|}]&][s7;%00-00 [%00-00 -|void Ok1() {]&][s7;%00-00 [%00-00 -|-|Foo"
" *x = this;]&][s7;%00-00 [%00-00 -|// local variable will not exist outside metho"
"d]&][s7;%00-00 [%00-00 -|// -> does not prevent Foo from being moveable]&][s7;%00"
"-00 [%00-00 -|}]&][s7;%00-00 [%00-00 -|void Ok2() {]&][s7;%00-00 [%00-00 -|-|mems"
"et(`&a, 0, sizeof(int));]&][s7;%00-00 [%00-00 -|// pointer will not exist outside"
" method]&][s7;%00-00 [%00-00 -|// -> does not prevent Foo from being moveable]&]["
"s7;%00-00 [%00-00 -|}]&][s7;%00-00 [%00-00 -|void Bad1() {]&][s7;%00-00 [%00-00 -"
"|-|foo = this;]&][s7;%00-00 [%00-00 -|// member variable foo exists outside metho"
"d]&][s7;%00-00 [%00-00 -|// -> makes Foo non-moveable]&][s7;%00-00 [%00-00 -|}]&]"
"[s7;%00-00 [%00-00 -|void Bad2() {]&][s7;%00-00 [%00-00 -|-|ptr = `&a;]&][s7;%00-"
"00 [%00-00 -|// pointer to subobject stored, ptr exists outside method]&][s7;%00-"
"00 [%00-00 -|// -> makes Foo non-moveable]&][s7;%00-00 [%00-00 -|}]&][s7;%00-00 ["
"%00-00 -|void Bad3() {]&][s7;%00-00 [%00-00 -|-|global`_foo = this;]&][s7;%00-00 "
"[%00-00 -|// pointer stored to global variable]&][s7;%00-00 [%00-00 -|// -> makes"
" Foo non-moveable]&][s0;%00-00C@5;2 [%00-00;3 -|-|][%00-00 }]&][s0;%00-00C@5;2 [%"
"00-00 -|-|void Bad4(Foo`& another) {]&][s0;%00-00C@5;2 [%00-00 -|-|-|another.Set("
"this);]&][s0;%00-00C@5;2 [%00-00 -|-|// pointer stored indirectly in object that "
"exist outside method]&][s0;%00-00C@5;2 [%00-00 -|-|// -> makes Foo non-moveable]&"
"][s0;%00-00C@5;2 [%00-00 -|-|}]&][s7;%00-00 [%00-00 };]&][s5; This requirements s"
"atisfies fairly large number of types, incidentally most of types you ever wanted"
" to store in container of elements of single type are moveable. Most important, a"
"ll [%00-00 NTL] containers [* are ]moveable.&][s5; Now we")
TOPIC_TEXT(
" have effective method how to organize storing of elements in containers. What w"
"e have to deal with is fact that being moveable is part of object's interface. To"
" make things safer we should disallow storing non-moveable elements in containers"
" requiring moveable ones. We need to have a way how to declare that type is movea"
"ble at compile time and also how to check it.&][s5; To achieve this goal, you can"
" mark moveable type using [%00-00* Moveable] base e.g.:&][s7;%00-00 [%00-00 class"
" SimpleString : Moveable<SimpleString> { ... }]&][s5;%00-00 [%00-00 or add you ca"
"n use ][%00-00* NTL`_MOVEABLE ][%00-00 macro to mark types where you cannot chang"
"e class interface:]&][s7;%00-00 [%00-00 NTL`_MOVEABLE(std`::string);]&][s5;%00-00"
" [%00-00 Now that we can mark types to be moveable, we need a way to check a type"
" for being moveable. You can do it by adding]&][s7;%00-00 [%00-00 AssertMoveable<"
"T>()]&][s5;%00-00 [%00-00 to some method of template that gets compiled for any t"
"emplate argument - destructor being the most obvious place. This function is in t"
"urn defined only if ][%00-00* T][%00-00  is marked as Moveable.]&][s5;%00-00 [%00"
"-00 Finally, time has come to deal with C`++ standard. Current C`++ defines memcp"
"y only for POD types. Moveable concept requires memcpy of non-POD types to be def"
"ined. In fact, difference between POD and Moveable non-POD types is existence of "
"constructor and non-virtual destructor. To get things work, all we need is that r"
"esult of memcpy-ing non-POD type ][%00-00* T ][%00-00 is same as memcpy-ing POD ]"
"[%00-00* T1 ][%00-00 type you would get by removing destructor and constructor fr"
"om ][%00-00* T][%00-00 . While this is still undefined by C`++, it is realy hard "
"to imagine optimal C`++ implementation that would break this rule. Indeed, all cu"
"rrent implementation we have met so far support moveable semantics in a way we ha"
"ve defined here. Performance and other gains realized using moveable concept are "
"too big to ignore.]")
