I am surprised that the following simple code won't compile (with gcc, version 4.8.1)
#include <string>
void test()
{
std::string* p = new std::string("Destruct me");
p->std::~string();
}
It says: error: scope ‘std’ before ‘~’ is not a class-name. Yet reading the standard, I would say the syntax says it should be "postfix-expresssion -> pseudo-constructor-name", where pseudo-constructor-name can be of the form "nested-name-specifier ~ type-name", and nested-name-specifier can be "identifier::".
Leaving out "std::" leads to the complaint that a class name was expected before the left paren, and putting it after the tilde to the complaint that a class name was expected before "::". After some trying I found that it will compile when written p->std::string::~string();
(but not when one writes p->std::string::~std::string();
instead). But qualifying the destructor with its own type name is not a neutral operation; I gather from the example in 12.4:13 of the standard (but curiously not from the normative text) that this forces the destructor of the exact static (base) class to be called, rather than as a virtual function that of (the most derived type of) the actual object pointed to. Here it makes no difference, but in similar cases it would; why would the syntax force exclusively using the static type?
However, with clang instead of gcc even the mentioned variant gives a syntax error. The error messages of clang are more amusing though, if you're in the mood for for this kind of humour when reading error messages: for p->std::string::~string();
it gives "expected the class name after '~' to name a destructor" (and so it does; one wonders which kind of class names would not name a destructor if prefixed by a tilde), and for my initial trial p->std::~string()
it retorts "qualified member access refers to a member in namespace 'std'" (again one wonders what is wrong with that; indeed the destructor to be called lives in the namespace 'std'). I've tried all 8 reasonable combinations (std:: and/or string:: before the tilde, and/or std:: after it) and none of them compile with clang.
I can make it compile, even with clang, using using std::string;
. But what I find curious is that I can find no indication in the standard that such a declaration was intended to be necessary in such cases.In fact I can find nothing that addresses the issue of calling the destructor of a namespace-qualified class at all. Am I missing something obvious?
As a final note, I'd like to add that it strikes me as odd that one have to use a namespace qualification at all when calling a destructor. Since this is member access from a well specified object (here *p
) shouldn't argument-dependent lookup make explicitly qualifying the namespace unnecessary?
In the standard, at:
therefore it would seem that
~string
should be looked up in the context of thestd::
namespace.In fact, considering that a corresponding home-made version works as follows on both GCC and Clang:
Live demo with clang++ Live demo with g++
I'll go ahead and say this is most likely a bug.
Apparently, given that
std::string
is reallystd::basic_string<char>
if you call:Live demo with clang++ Live demo with g++
then everything compiles fine.
I still remain of the idea that this a bug, considering that the following example (taken from the standard), shows that
typedef
s should also work:This notion, together with §3.4.5/3 should guarantee that:
should work.
2019 update: Starting from C++17, you can use
std::destroy_at
as follows:It's much simpler and follows the principle of not using "primitive constructs" (such as
new
/delete
expressions) in modern C++.