Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Explicit destructor call - problem with basic types and types from other namespaces

219 views
Skip to first unread message

PiotrN

unread,
May 9, 2012, 3:26:42 PM5/9/12
to
Hello,

Two questions:
1) Why I cannot call destructor for builtin types like int:
int a;
int* p = new (&a) int(7);
p->~int();

I found in the NET that standard says: "The notation for explicit call
of a destructor can be used for any scalar type name. Allowing this
makes it possible to write code without having to know if a destructor
exists for a given type. "
And typedef int is "scalar type name" but int is not - so it works the
following:
typedef int INT;
p->~INT();
Why standard does allow calling destructor on typedef (and template
typename) - but it has objections to plain type? Is there any
rationale for this?

2) Why C++ (gcc-4.3.4) has objections to this syntax:

p->std::~string();

of course this works well:

using namespace std;
p->~string();


Thanks in advance,
Piotr




--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Daniel Krügler

unread,
May 9, 2012, 5:57:02 PM5/9/12
to
Am 09.05.2012 21:26, schrieb PiotrN:
> Two questions:
> 1) Why I cannot call destructor for builtin types like int:
> int a;
> int* p = new (&a) int(7);
> p->~int();
>
> I found in the NET that standard says: "The notation for explicit call
> of a destructor can be used for any scalar type name. Allowing this
> makes it possible to write code without having to know if a destructor
> exists for a given type. "

Yes, this is roughly the rationale for it: To be able to write generic
code without much trickery to discriminate scalar types from class
types. The more precise rule is that the pseudo-destructor name is valid
for scalar types only, if these are provided as /type-name/ (like a
typedef) or a decltype-specifier (like: decltype(0)).

> And typedef int is "scalar type name" but int is not - so it works the
> following:
> typedef int INT;
> p->~INT();
> Why standard does allow calling destructor on typedef (and template
> typename) - but it has objections to plain type? Is there any
> rationale for this?

Only a weak one: Once you are in non-template code, you have knowledge
of the specific type, so why bothering with writing a no-op? This *is*
really a weak argument, because you have the same problem once you would
try to write a generic macro. In other words: I wish, we would not have
this constraint to support the pseudo-destructor only for type-names and
decltype-specifiers when we have a non-class type.

> 2) Why C++ (gcc-4.3.4) has objections to this syntax:
>
> p->std::~string();
>
> of course this works well:
>
> using namespace std;
> p->~string();

You can write this as:

p->std::string::~string();

HTH & Greetings from Bremen,

Daniel Krügler

Francis Glassborow

unread,
May 9, 2012, 6:04:59 PM5/9/12
to
On 09/05/2012 21:15, Asger Joergensen wrote:
> Hi PiotrN
>
> PiotrN wrote:
>
>> Hello,
>>
>> Two questions:
>> 1) Why I cannot call destructor for builtin types like int:
>> int a;
>> int* p = new int[7];
>> p->~int();
>
> You never call the destructor directly you use delete instead:

Untrue. You use a destructor call whenever you want to retain the
underlying memory
>
> int* p = new int[7];
>
> ....do some work
>
> delete[] p;

All that is fine until you are using a placement new in a context where
calling delete is wrong. For example, when using a memory pool.


The real problem with the above is that if you are using a dtor call you
cannot apply it to p because p is a pointer to an array.

However there is also the problem that you cannot use the dtor syntax on
a buitin type by its formal name only when using an alias either
provided through a typedef or by a template parameter.

I think the argument is that if you know the name you know it is trivial
so nothing needs to be done. That you can use the syntax on an alias
provided through a typedef is an artefact of way we provided template
type names. It is also not irrational because if you want to change some
code by replacing a usage of int by a usage of some other type you would
want it to continue to work. E.g.

I write all by code using:

typedef int year;

and at a later stage decide I want to provide a real year type (called
my_year_type which has a non-trivial dtor then I can simply replace the
typedef with:

typedef my_year_type year;

and the code should continue to work.

Another way of looking at this is that an int is an int and there is no
way you can make it anything else but and INT may stop being an int and
become anything else the programmer wants it to be which may not be a
type with a trivial dtor.

Johannes Schaub

unread,
May 9, 2012, 6:04:26 PM5/9/12
to
Am 09.05.2012 21:26, schrieb PiotrN:
> Hello,
>
> Two questions:
> 1) Why I cannot call destructor for builtin types like int:
> int a;
> int* p = new (&a) int(7);
> p->~int();
>
> I found in the NET that standard says: "The notation for explicit call
> of a destructor can be used for any scalar type name. Allowing this
> makes it possible to write code without having to know if a destructor
> exists for a given type. "
> And typedef int is "scalar type name" but int is not - so it works the
> following:
> typedef int INT;
> p->~INT();
> Why standard does allow calling destructor on typedef (and template
> typename) - but it has objections to plain type? Is there any
> rationale for this?
>

While I don't know the rationale, I think it's likely that it's because
plain "~int()" is not very useful (at least not as long as it is a
"noop", like currently).

The utility of a pseudo destructor call like "p->~T()" with T being
"int" is that you can say "p->~T()" in a *template* disregarding of
whether "T" actually is a class or not. In these cases you use a
template parameter which is a "type-name".


> 2) Why C++ (gcc-4.3.4) has objections to this syntax:
>
> p->std::~string();
>

Because the syntax is "p->~ typename", so you need to say

p->~std::string();

Note that in this call, this actually calls the destructor. It is not a
pseudo destructor call like for the "int" case and hence it is not a noop.

> of course this works well:
>
> using namespace std;
> p->~string();
>
>

This works as long as you have the "using namespace std;" or a "using
std::string;" in place. If you haven't, then "string" is not known as a
class name and you either need to use the above, or the below
(std::string is just a typedef for a particular "basic_string" template
specialization having "char" as element type).

p->~basic_string();

This will find the implicitly declared "basic_string" type name in the
std::string class (if you say "p->~foo", then "foo" is searched both in
the current scope and in the scope of "p") and is equivalent to
"p->~std::string();", as far as the effects are concerned.

Seungbeom Kim

unread,
May 10, 2012, 2:38:54 PM5/10/12
to
On 2012-05-09 15:04, Francis Glassborow wrote:
> On 09/05/2012 21:15, Asger Joergensen wrote:
>>
>> int* p = new int[7];
>>
>> ....do some work
>>
>> delete[] p;
>
> The real problem with the above is that if you are using a dtor call you
> cannot apply it to p because p is a pointer to an array.

p is a pointer to int. So, I guess your point is that there's no
such thing as an "array destructor call" and/or that you may apply
a destructor call only to each element of the array manually.

--
Seungbeom Kim

Johannes Schaub

unread,
May 10, 2012, 2:42:36 PM5/10/12
to
Am 10.05.2012 00:04, schrieb Johannes Schaub:
> Am 09.05.2012 21:26, schrieb PiotrN:
>> 2) Why C++ (gcc-4.3.4) has objections to this syntax:
>>
>> p->std::~string();
>>
>
> Because the syntax is "p->~ typename", so you need to say
>
> p->~std::string();
>
> Note that in this call, this actually calls the destructor. It is
> not a pseudo destructor call like for the "int" case and hence it is
> not a noop.
>

The syntax I showed above is aswell invalid. The correct syntax for
the qualified name call is shown by Daniel Krügler.

I'm sorry for the confusion.

PiotrN

unread,
May 10, 2012, 2:49:46 PM5/10/12
to
> > 2) Why C++ (gcc-4.3.4) has objections to this syntax:
>
> > p->std::~string();
>
> Because the syntax is "p->~ typename", so you need to say
>
> p->~std::string();
>

The above does not work: (gcc-4.3.4) "error: expected class-name
before ‘::’ token"...

>
> p->~basic_string();
>

This one works perfect. Thanks. It is very easy to forget that string
is just typedef to basic_string.

Daniel's solution below works well too:

p->std::string::~string();

But I am afraid it can't be used for virtual desctructor call.


Thanks,
Piotr

mkl...@gmail.com

unread,
May 18, 2012, 5:25:37 PM5/18/12
to
Hi!

Am Mittwoch, 9. Mai 2012 23:57:02 UTC+2 schrieb Daniel Krügler:
> Am 09.05.2012 21:26, schrieb PiotrN:

> [...]

> > 2) Why C++ (gcc-4.3.4) has objections to this syntax:
> >
> > p->std::~string();
> >
> > of course this works well:
> >
> > using namespace std;
> > p->~string();
>
> You can write this as:
>
> p->std::string::~string();

Wow. Makes an advanced exam question IMO.

I stumbled upon this thread because of a recent discussion about
placement new on Lua's mailing list.

Seeing this I immediately wondered how this works together with
templates. Trying

template< typename T >
void testPn( const T &v ) {
char data[ sizeof( T ) ];
T *t = new ( data ) T( v );
t->~T();
}

with testPn< std::string >( "asdf" ) I was delighted that it worked.
That shows that templates are more than a mildy intelligent
preprocessor...

Regards,
Matthias
0 new messages