//
//  Creation and destruction time
//

An object can be created as:

- named automatic object
    C - when declaration is encountered
    D - when the program exits the block, in reverse order

- free store object
    C - new
    D - delete

- nonstatic member object
    C - when the object which is created, in the order of declaration
    D - when the object is destroyed, in reverse order

- array element
    C - when the array is created, in growing index order
    D - when the array is destroyed, in reverse order

- local static object
    C - when first time the declaration is evaluated
    D - at the end of the program

- global, namespace or class static object
    C - at the start of the program
    D - at the end of the program

- temporary object
    C - created as part of the evaluation of an expression
    D - at the end of the full expression

- placement new
    C - new
    D - delete

- member of a union
    may not have constructor or destructor (the member)
    (a union also may not have static field)


Free store:

    date *p = new date;
    date *q = new date(*p);
    date *s = new date[10];

    delete p;
    delete p;   // !! runtime error
    delete s;   // !! runtime error



//    
//  Creation of subobjects
//

class list
{
public:
     list();
    ~list();

    // ...
private:
    // this order is the relevant:
    int  id;
    list *next;
    list *prev;
};


// will be automatically rearranged: id(nid), next(0), prev(0)
list::list() : id(nid), prev(0), next(0)
{
    ++nid;
}

//
//  Construction of statics 
//
struct X
{
    X(int i)
    {
        x = i;
        std::cerr << x << std::endl;
    }
    int x;
};

void f()
{
    // std::cerr << "enter into f(), ix.x = " << ix.x << std::endl;
    static X ix(0);
    std::cerr << "enter into f(), ix.x = " << ix.x << std::endl;
    ++ix.x;
    if ( ix.x > 5 )
    {
        static X iy(ix.x);
        static X iz(ix);    // copy constructor
    }
}

int main()
{
    for ( int i = 0; i < 10; ++i)
        f();
    return 0;
}


//
// arrays
//

#include <vector>

struct X { X(int i) { x = i; }; int x; };
struct Y {                      int y; };

int main()
{
    const int n = 4;
          int k = 4;

 // X x1[n];    // no default constructor
    X x2[n] = { 1, 2, 3, 4};
    Y y1[n];
    Y y2[k];    // k is non-const: error by standard 

 // X *xp = new X[k];   // no default constructor
    Y *yp = new Y[k];

 // std::vector<X> xv(10);  // no default constructor
    std::vector<Y> yv(10);

    delete [] yp;
}

//
//  arrays are not polymorphic!
//

#include <iostream>

using namespace std;

struct Base
{
    Base() { cout << "Base" << " "; }
    virtual ~Base() { cout << "~Base" << endl; }

    int i;
};
struct Der : public Base
{
    Der() { cout << "Der" << endl; }
    virtual ~Der() { cout << "~Der" << " "; }

    int it[10]; // sizeof(Base) != sizeof(Der) 
};

int main()
{
    Base *bp = new Der;
    Base *bq = new Der[5];

    delete    bp;
    delete [] bq;   // this causes runtime error 
}

//
// Temporaries
//

Temporary objects:

- Created under the evaluation of an expression
- Destroyed when full expression has been evaluated

void f( string &s1, string &s2, string &s3)
{
    const char *cs = (s1+s2).c_str();
    cout << cs;     // Bad!!

    if ( strlen(cs = (s2+s3).c_str()) < 8 && cs[0] == 'a' ) // Ok
            cout << cs;     // Bad!!
}

// the correct way:
void f( string &s1, string &s2, string &s3)
{
    cout << s1 + s2;
    string s = s2 + s3;

    if ( s.length() < 8 && s[0] == 'a' )
        cout << s;
}

// another correct way:
void f( string &s1, string &s2, string &s3)
{
    cout << s1 + s2;
    const string &s = s2 + s3;

    if ( s.length() < 8 && s[0] == 'a' )
        cout << s;  // Ok
} // s1+s2 destroyes here: when the const ref goes out of scope