473,761 Members | 8,933 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

explicit call of constructor and destructor

Hi Everyone,

I have the following code and i'm able to invoke the destructor
explicitly but not the constructor. and i get a compile time error
when i invoke the constructor, why is this so?

class Trial
{
public: Trial()
{
printf("Trial\n ");
}
~Trial()
{
printf("~Trial\ n");
}
};

int main()
{
Trial obj;
obj.Trial(); // Causes compile time error
obj.~Trial();
}
Dec 3 '07
12 7211
On Dec 4, 8:47 am, Abhishek Padmanabh <abhishek.padma n...@gmail.com>
wrote:
On Dec 3, 11:14 pm, "Alf P. Steinbach" <al...@start.no wrote:
* Abhishek Padmanabh:
Calling the destructor twice is undefined behavior. The only place
where explicitly calling the destructor is required and justified is
when you used placement new to do the constructor over a pre-allocated
buffer.
That's a bit too sweeping a statement, I'm afraid.
Better to say, as a novice, don't call destructors.

Where else would one call the destructor if they are not using
placement new?
This was unanswered, where else would you invoke the destructor, as in
objectOfClassA. ~A(), if not in the context of in-place construction?
Dec 5 '07 #11
On Dec 5, 6:03 am, Abhishek Padmanabh <abhishek.padma n...@gmail.com>
wrote:
On Dec 4, 8:30 pm, James Kanze <james.ka...@gm ail.comwrote:
On Dec 4, 4:47 am, Abhishek Padmanabh <abhishek.padma n...@gmail.com>
wrote:
[...]
Ok, thanks for that. So then, how is an operator new overload
(which can be called an allocation function, right?) different
from a user defined placement new form (not using the one for
in place construction as available in <new>)?
Attention. We're dealing with two different things here. You
can overload the global operator new function, by providing one
with a different signature, and you can replace the standard
operator new function with one of your own.

In the second case, your function must have exactly the same
signature and the same semantics as the original, including
throwing std::bad_alloc (or a class derived from it) in case of
insufficient memory. And there *is* a corresponding operator
delete function for this, so any new expression using it will
require the compiler to generate code ensuring that the operator
delete function is called if the constructor exits via an
exception.

In the first case, of course, it's up to you. You can either
report failure by means of bad_alloc, or you can declare the
function throw(), and return a null pointer. You can provide a
corresponding placement delete, which will be called if the
constructor exits via an exception, or not (in which case
nothing will be called).
operator new/operator delete overloads should match the
signature of their global forms provided by the compiler.
If the signatures match, then it's not an overload, it's a
replacement.
And then when the objects of the class, for which these are
overloaded, are created using new expression, use the operator
new overload for allocation and the corresponding operator
delete for deallocation.
If placement allocation function and placement deallocation
functions also manage allocation and deallocation then what is
different between these and the above overloads?
They use different algorithms?

The most frequent case I've seen is something like:

void* operator new( size_t n, MemoryPool& ) ;
void operator delete( void* p, MemoryPool& ) ;

Invoked by something like:

MemoryPool pool1 ;
T* p = new ( pool1 ) T ;

In this case, you probably need the placement delete, since if
the constructor fails, you want to delete the memory. (Or maybe
the pools are garbage collected in some way, and you don't need
it.)
Just that if the signature if a direct match with operator
new/operator delete,
If the signature is a direct match, they are replacements, not
overloads.
they are overloads else they are placement allocation
functions?
Also, referring to the example as in 5.3.4 (20) as below:
struct S {
// Placement allocation function:
static void* operator new(std::size_t , std::size_t);
// Usual (non-placement) deallocation function:
static void operator delete(void*, std::size_t);
};
S* p = new (0) S; // ill-formed: non-placement deallocation function
matches
// placement allocation function
This is a special case. The problem with member operator delete
is that the non-placement form can have one of two different
signatures. Which leads to an ambiguity if the placement form
of new takes a size_t as it's additional argument: is the
operator delete, above, a placement form (which should be called
if the constructor in a corresponding placement new throws), or
is it the standard form (in which case, it will only be called
if non-placement new is used).

On the whole, my comments didn't take member overloads of
operator new into consideration, but except for the fact that
the non-placement delete can have one of two different
signatures, the rules are pretty much the same. Of course, the
name lookup rules means that a placement operator new in a class
will hide the global non-placement operator, so objects of that
type can only be created by placement new.

More generally, overloading operator new and operator delete can
be tricky; it's not something for beginners.
The standard also says (in 18.5.1.3 - Placement forms) that the
placement form function is reserved and a C++ program may not define
them that would displace these? Is that specific to the form as below:
void* operator new(std::size_t size , void* ptr ) throw();
and if I had a different argument list for this - would that be
allowed?
Exactly. You are not allowed to replace this form of placement
new, since much of the standard library code probably depends on
it having exactly the semantics provided for by the standard
library.

Note that at a language level, there's nothing special about
this level. As far as the compiler is concerned, the new
expression behaves as always: it calls an allocator function to
acquire the memory, then the constructor of the object. Because
this particular placement new is declared nothrow, the compiler
will also generate code to check that the returned pointer is
not null before calling the constructor. Because the library
also declares a corresponding placement delete, the compiler
will also generate code to ensure that it is called if the
constructor exits via an exception. (I've often wondered about
this; the semantics of the corresponding placement delete are to
do nothing, so I don't see the reason behind having it, and
getting it called. Perhaps just to prevent user code from
accidentally declaring it.)

And of course, by using this "allocator" , the language itself
never violates the rule that a constructor cannot be invoked
without memory allocation.

The more I think about it, the more I think that constructors
really are somewhat special. All other member functions,
including the destructor, are either static or non-static. If
they're static, there's no object, and not this pointer. If
they're non-static, they are always called on a specific object,
whose address becomes the this pointer. The constructor is
special in that it not called on an object---before the
constructor is called, the object doesn't exist---but that it
has a this pointer. So it's really a third type of member
function, not really static (since it has a this pointer), but
not really non-static either (since you don't need an object to
call it). The standard could have provided a special syntax,
say p->TypeName() (where p would have type void*, or be
convertible to a void*), to call the constructor, without any
allocation. But this would be a special syntax: the "placement
new" trick works just as well, and the operation isn't frequent
enough to warant a special syntax.

--
James Kanze (GABI Software) email:ja******* **@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientier ter Datenverarbeitu ng
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Dec 5 '07 #12
First off, thank you very much for the help so far!

On Dec 5, 5:36 pm, James Kanze <james.ka...@gm ail.comwrote:
On Dec 5, 6:03 am, Abhishek Padmanabh <abhishek.padma n...@gmail.com>
wrote:
operator new/operator delete overloads should match the
signature of their global forms provided by the compiler.

If the signatures match, then it's not an overload, it's a
replacement.
Yes, exactly. I think this was the basic mis-understanding I was
having. Let's see if it is gone now.
And then when the objects of the class, for which these are
overloaded, are created using new expression, use the operator
new overload for allocation and the corresponding operator
delete for deallocation.
If placement allocation function and placement deallocation
functions also manage allocation and deallocation then what is
different between these and the above overloads?

They use different algorithms?
Right, now I think what I was confused about. There are certain
overloads to operator new/operator delete that can only be called
using the placement new form/expression. These overloads are called
placement allocation/deallocation forms. I was thinking that these
overloads were different from the placement allocation/deallocation
forms which I think is wrong. Could you please see my understanding
below and confirm on those points?
The most frequent case I've seen is something like:

void* operator new( size_t n, MemoryPool& ) ;
void operator delete( void* p, MemoryPool& ) ;

Invoked by something like:

MemoryPool pool1 ;
T* p = new ( pool1 ) T ;

In this case, you probably need the placement delete, since if
the constructor fails, you want to delete the memory. (Or maybe
the pools are garbage collected in some way, and you don't need
it.)
Should it be deleting the memory? Shouldn't the MemoryPool be the one
managing it? And this operator delete doing just some pointer
adjustments? Please see below as well.
Just that if the signature if a direct match with operator
new/operator delete,

If the signature is a direct match, they are replacements, not
overloads.
they are overloads else they are placement allocation
functions?
Also, referring to the example as in 5.3.4 (20) as below:
struct S {
// Placement allocation function:
static void* operator new(std::size_t , std::size_t);
// Usual (non-placement) deallocation function:
static void operator delete(void*, std::size_t);
};
S* p = new (0) S; // ill-formed: non-placement deallocation function
matches
// placement allocation function

This is a special case. The problem with member operator delete
is that the non-placement form can have one of two different
signatures. Which leads to an ambiguity if the placement form
of new takes a size_t as it's additional argument: is the
operator delete, above, a placement form (which should be called
if the constructor in a corresponding placement new throws), or
is it the standard form (in which case, it will only be called
if non-placement new is used).

On the whole, my comments didn't take member overloads of
operator new into consideration, but except for the fact that
the non-placement delete can have one of two different
signatures, the rules are pretty much the same. Of course, the
name lookup rules means that a placement operator new in a class
will hide the global non-placement operator, so objects of that
type can only be created by placement new.
Regarding the 2 forms (and this special case), please see below.
More generally, overloading operator new and operator delete can
be tricky; it's not something for beginners.
Sorry, I know I am not an expert but that hurts. I just want to
understand it else it will keep haunting me.
The standard also says (in 18.5.1.3 - Placement forms) that the
placement form function is reserved and a C++ program may not define
them that would displace these? Is that specific to the form as below:
void* operator new(std::size_t size , void* ptr ) throw();
and if I had a different argument list for this - would that be
allowed?

Exactly. You are not allowed to replace this form of placement
new, since much of the standard library code probably depends on
it having exactly the semantics provided for by the standard
library.
Yes, these cannot be replaced but overloaded. :)
Note that at a language level, there's nothing special about
this level. As far as the compiler is concerned, the new
expression behaves as always: it calls an allocator function to
acquire the memory, then the constructor of the object. Because
this particular placement new is declared nothrow, the compiler
will also generate code to check that the returned pointer is
not null before calling the constructor. Because the library
also declares a corresponding placement delete, the compiler
will also generate code to ensure that it is called if the
constructor exits via an exception. (I've often wondered about
this; the semantics of the corresponding placement delete are to
do nothing, so I don't see the reason behind having it, and
getting it called. Perhaps just to prevent user code from
accidentally declaring it.)
Yes, it looks pretty useless but it is good to have a consistent
semantics. Here is my understanding as of now. Could you please
suggest if it looks right or wrong?

The global operator new and delete have the following signatures:

1. void* operator new(std::size_t ) throw(std::bad_ alloc); //single
object form throws std::bad_alloc
2. void* operator new[](std::size_t) throw(std::bad_ alloc); //array
form - throws bad alloc
3. void* operator new(std::size_t size , const std::nothrow_t& )
throw(); //nothrow new
4. void* operator new[](std::size_t size , const std::nothrow_t& )
throw(); //no throw array form of new
5. void operator delete(void*) throw(); //single object form
6. void operator delete[](void*) throw(); //array form
7. void operator delete(void* , const std::nothrow_t& ) throw(); //
corresponds to nothrow new
8. void operator delete[](void* , const std::nothrow_t& ) throw(); //
corresponds to nothrow array form of new

To use 3 and 4 (related to 7 and 8 versions of operator delete),
placement form of new is used wherein there is an argument list
attached to new, as in A * ptr = new (nothtow) A();

Another set of overload for operator new/operator delete are provide
that are used for in-place construction. They are declared as below:

9. void* operator new(std::size_t size , void* ptr ) throw();
10. void* operator new[](std::size_t size , void* ptr ) throw();
11. void operator delete(void* ptr , void*) throw();
12. void operator delete[](void* ptr , void*) throw();

These are provided by the standard library and these can not be
replaced in the sense that no operator new/operator delete sets would
be defined by a program with the above 4 signatures (9 through 12).
These two operator new's don't do allocation and hence operator
delete's don't do any deallocation. The operator new just returns the
pointer ptr (no other action performed) and operator delete does not
perform any action. The operator delete is just a function that gets
called in case the constructor of the object being constructed on ptr
throws an exception.

These come to use when doing in-place construction as below:

char* buffer = new char[sizeof(A)];
A * ptrToA = new (buffer) A();
ptrToA->~A();
delete[] buffer;

If class provides replacements for functions 1 through 8 in their
class, they must have the same signature as shown in 1-8. And then
when that object is created via new expression or the placement new
nothrow form, these replacement versions will be called and
corresponding operator deletes will be called when the object is to be
normally destroyed or if the constructor of that class throws an
exception.

There can be other overloads to operator new/operator delete that can
only be called using placement new expression (the below can have any
more number of arguments - the argument list between the operator new
and delete must match except for the first argument). For example:

13. void* operator new(std::size_t size, MemoryPool& mempool) throw();
14. void* operator new[](std::size_t size, MemoryPool& mempool)
throw();
15. void operator delete(void* ptr, MemoryPool& mempool) throw();
16. void operator delete[](void* ptr, MemoryPool& mempool) throw();

One example way to use this is that the operator new would be checking
what portion of that pool they can utilize and make pointer
adjustments on the pool and return a pointer to the location wherein
the construction of the object can take place. Ideally, operator
delete should not deallocate the memory because it is part of the pool
and is being managed by the pool. It would work the same way as the
operator delete mentioned in 11 and 12. Maximum they can do it, using
MemoryPool's interface, can mark the area re-usable on which the
object was constructed since the destructor must have got called
before this operator delete gets called. If the operator delete is
deallocating memory then the advantage of a pool is lost since the
intent is to minimize system calls for acquiring and freeing memory.
It is not mandatory that you have this behavior but I am just thinking
from the point of view that the MemoryPool I am using is to allocate a
huge chunk of buffer at start-up and keep re-using it to create
objects on without making repeated calls to the system for memory
acquisition and freeing.

Now, coming to the special case,

17. void* operator new(std::size_t , std::size_t);
18. void operator delete(void * ptr, size_t);

This is still a problem for me. How is the operator delete a non-
placement deallocation function? The non-placement deallocation
function would have the signature matching 5 and 6. Right? Because
only 1 and 2 forms of operator new and their replacements are the only
ones that can be called by the new expression. For all the rest, the
placement new form must be used to supply those additional arguments.

If 18 is the second form of the non-placement allocation function,
(because you say there are 2 forms, one is the form in 5 and 6, I
believe this is the second one that you are pointing to), could you
please quote the standards section that says so?

Please bear with me. :) Thanks very much, once again.
Dec 5 '07 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
7843
by: tzach | last post by:
Call constructor on an already existing instance? I like to execute the constructor logic, including all the class member constructors, on an existing instance (with out executing the destructor). Can it be? Thanks.
3
2864
by: Jacques Labuschagne | last post by:
Hi all, Is it legal to kill an object and build a new one of the same type in its memory? class A{ int i; public: explicit A(int value): i(value){} };
6
7517
by: Christoph Bartoschek | last post by:
Hi, gcc 3.4 rejects the following program: class T { public: T() : a(3) {} explicit T(T const & other) : a(other.a) {} private: int a;
23
5182
by: Fabian Müller | last post by:
Hi all, my question is as follows: If have a class X and a class Y derived from X. Constructor of X is X(param1, param2) . Constructor of Y is Y(param1, ..., param4) .
8
2980
by: trying_to_learn | last post by:
Why do we need to explicitly call the copy constructor and the operator = , for base class and member objects in composition? ....book says "You must explicitly call the GameBoard copy-constructor or the default constructor is automatically called instead" Why cant the compiler do this on its own. if we are making an object through copr construction for an inherited class , then why not simply call the corresponding copy constructors for...
20
2751
by: frs | last post by:
For memory economization, I need to get rid if the virtual destructor. Under this constraint I get caught up in a design, where I need to call a destructor of a derived class from a base class. Briefly it could be displayed like the code below. It ends up deleting the member 'x' of 'B' twice. Why? Is there a way around? Thanks Frank
9
1510
by: Rennie deGraaf | last post by:
I'm writing a class similar to this: #include <iostream> using namespace std; template<class t> class Foo { private: class Bar {
7
2710
by: dragoncoder | last post by:
Hello experts, I have the following code me. =cat mystring.h #include<iostream> using namespace std; class mystring {
7
2133
by: michael | last post by:
Hi All, I have written the following to illustrate a problem. I know I have some magic numbers etc please ignore them. What I do not follow is why the line marked results in a call to the destructor for the object. Can someone please explain it for me? #include <iostream>
0
9554
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9376
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9988
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9923
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9811
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8813
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5405
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3911
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
2788
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.