// @topic T51011 Miscellaneous small samples developed in class
// @brief 10/11/2012 -- the need for a copy constructor

class DynArray {
public:
    int* ptr_mem;
    // constructors/destructor
    DynArray()
    {
        ptr_mem = new int[ 3 ];
    }

    // copy constructor
    DynArray( DynArray& arr )
    {
        ptr_mem = new int[ 3 ];
        ptr_mem[ 0 ] = arr.ptr_mem[ 0 ];
        ptr_mem[ 1 ] = arr.ptr_mem[ 1 ];
        ptr_mem[ 2 ] = arr.ptr_mem[ 2 ];
    }

    // specific constructor
    DynArray( DynArray& arr, bool copy_flag )
    {
        ptr_mem = new int[ 3 ];
        if ( copy_flag ==  true ) { 
            ptr_mem[ 0 ] = arr.ptr_mem[ 0 ];
            ptr_mem[ 1 ] = arr.ptr_mem[ 1 ];
            ptr_mem[ 2 ] = arr.ptr_mem[ 2 ];
        }
    }

    // conversion constructor
    explicit DynArray( int intial_size )
    {
        ptr_mem = new int[ intial_size ];
    }

    // destructor
    ~DynArray()
    {
        delete[] ptr_mem;
    }
};//class DynArray

// example of a function that creates and returns a copy of an object:
DynArray blah( DynArray arr )
{
    std::cout << arr.ptr_mem[ 0 ] << '\n';
    return DynArray( arr );
}

// this function does not cause the need for a copy constructor
void blah( DynArray& arr )
{
    std::cout << arr.ptr_mem[ 0 ] << '\n';
}

// NOTE: this program could crash if the copy constructor wasn't
// defined for DynArray, because "shallow" copies of the object
// would attempt to delete[] the same dynamic memory more than once!
// The copy constructor above makes a "deep" copy: new memory block
// is allocated, then the data is copied over.
int main()
{
    DynArray arr1;
    DynArray& refst1 = arr1; // example of a reference
    arr1.ptr_mem[ 0 ] = 10;
    arr1.ptr_mem[ 1 ] = 20;
    arr1.ptr_mem[ 2 ] = 30;

    DynArray arr2; // using the default constructor
    arr2.ptr_mem[ 0 ] = 12345; // use the object
    DynArray arr3 = blah( arr1 ); // copy constructor is invoked before function is called
    DynArray arr4 = refst1; // copy constructor is invoked
    arr4.ptr_mem[ 1 ] = 222222; // use the object

    DynArray arr5 = arr1; // copy constructor
    DynArray arr6( arr1, false ); // specific constructor
    DynArray arr7( arr1, true ); // specific constructor
    DynArray arr8 = 100;  // conversion constructor
    DynArray arr9( 100 ); // conversion constructor

    blah( DynArray( 200 ) ); // conversion constructor is invoked (not a copy constructor)

    // this will not compile if conversion constructor was made explicit:
    blah( 300 );

    // strange ways to instantiate an integer using "constructor" syntax:
    int x( 5 );          // use constructor syntax to initialize x
    int y = int( 0.5 );  // convert double to int
    int z = int();                    // a default value for an int is...
    std::cout << "z==" << z << "\n";  // ...zero

    return 0;
}