C++/calling constructor explicitely
Expert: Ralph McArdell - 9/10/2011
Questionhi Ralph ,
class sample
{
int id;
float sal;
public:
sample()
{
cout<<"Sample created"<<endl;
}
~sample()
{
cout<<"Sample Destroyed"<<endl;
}
};
int main()
{
{
sample *s = new sample();
sample();
}
cin.get();
return 0;
}
In this program i am calling constructor explicitly...
so does sample created object created ..? how this memory get freed a d how we can access this object as i am not referencing it with any variable...
Thanks
Bhupal.
AnswerWell I am not sure what you mean when you say "so does sample created object created ..?" This I am afraid is a fairly meaningless phrase, but will run through what is going on in the hope I answer what you were asking about.
In the { } inner block of main, the first line:
sample *s = new sample();
creates a new object of type sample dynamically on the free store and assigns a pointer to this object to the local variable s. The next line:
sample();
creates a temporary sample object on the stack frame of the function call to main. As it is not assigned to anything it is destroyed at the end of the statement in which it is created in a similar manner to all automatic objects when they go out of scope.
Note that as s points to a dynamically allocated sample object and there is no delete s; statement the object pointed to by s is never properly destroyed, although desktop, workstation and server class operating systems will clean up a process' resources when it is destroyed so the raw memory used by the object pointed to by s will not be lost for reuse by the system for ever.
You might like to expand your experimental code something like so:
int main()
{
{
sample *s = new sample();
cout << "After dynamic sample object creation, before temporary sample object creation" << std::endl;
sample();
cout << "After temporary sample object creation, before local sample object creation" << std::endl;
sample ls;
cout << "After local sample object creation, before closing of inner block" << std::endl;
}
cout << "After closing of inner block" << std::endl;
cin.get();
return 0;
}
Here I have added a named local variable ls of type sample and added progress trace outputs after / before each point of interest. The output should look something like so:
Sample created
After dynamic sample object creation, before temporary sample object creation
Sample created
Sample Destroyed
After temporary sample object creation, before local sample object creation
Sample created
After local sample object creation, before closing of inner block
Sample Destroyed
After closing of inner block
The first "Sample created" line is due to the dynamically created sample object whose pointer is assigned to s.
The second "Sample created" line is immediately followed by a "Sample destroyed" line and is due to creation and then immediate destruction of the temporary sample object.
The third "Sample created" line is due to the added local sample object. As can be seen it is destroyed at the closing of the inner block - as is the case for all local objects - they go out of scope at the end of the block they are defined in and are destroyed at this point, whether due to code execution normally ending the block or due to an exception being thrown.
Note that s is also destroyed on the closing of the inner block but s is a pointer type and pointer types have do-nothing destructors. Specifically note that it is the _pointer_ that is destroyed and _not_ what it points to.
As the object pointed to by s is never destroyed (by an explicit delete) its destructor is never called so there is no third "Sample destroyed" line output.
And yes the temporary sample object cannot be accessed beyond the statement it is created on, but this does not mean it cannot be accessed:
sample().some_instance_member_function_of_sample();
for example (assuming you add some_instance_member_function_of_sample as a public instance member function to sample), or we could use such temporary objects as function call arguments:
function_taking_a_sample_by_value( sample() );
function_taking_a_sample_by_reference_to_const( sample() );
or in other expressions. Note that we can pass a temporary object by value - as a copy will be made, or by reference to constant - as this implies the state of the argument is not modified. However we cannot pass a temporary by reference to a non-constant object as doing so implies that the state of the referenced object will be changed in the function call - and these changes would be lost and useless in the case of temporary object and confusing if such a temporary were created implicitly by the compiler for type conversion purposes as then it would not be clear from the code why the object passed did not receive the expected changes (because the compiler created temporary received them instead).
Of course, as hinted on above, such uses of temporary objects are usually more interesting if the type of the temporary object created can be constructed from one or more other objects or values. For example if you require an object of one type but have an object of some other type then if the required type has a single argument constructor that can accept an object of the type of the object we have then we can create (construct) a temporary object of the required type in order to convert the value we have to the required type. One example that crops up now and again with char values is if we want to display the numeric value of a char rather than the character it represents. If we just do something like so:
char a('A');
std::cout << a << std::endl;
then we just get A output and not the value that is used to represent A in the character set used (65 if it is an ASCII based character set as is the common case these days). To get the underlying numeric value used to represent A in the character set we need to convert the char to another, non-character, integer type - which we can do by constructing a temporary int (for example) from the char value and outputting this temporary int:
std::cout << int(a) << std::endl; // or even std::cout << int('A') << std::endl;
In fact any class that has constructors that take a single argument might, as mentioned above, be used by the compiler to implicitly convert a value of one type to temporary objects of such class types if doing so will allow an expression or function parameter to be valid. That is the compiler _will_ use such single argument accepting constructors to create temporary objects for type conversion purposes if necessary. Obviously this is not always desirable or even sensible and in fact could create ambiguities by causing more function overloads to be equally valid causing unexpected compilation failures. In such cases where we do not wish such single argument accepting constructors to be used by the compiler for implicit creation of temporary objects we can mark the constructor as explicit:
class HolderOfThings
{
// ...
public:
// ...
// Mark constructor as explicit to prevent it being considered for implicitly
// converting size_t integer values to (temporary) HolderOfThings objects:
explicit HolderOfThings( size_t number_of_things_held ) /* ... */
//...
};
Hope this helps.