Re: Explicit destructor call - problem with typedef from other
namespace
Am 13.05.2012 11:49, schrieb PiotrN:
> Hello,
>
> I started similar thread in past week:
>
>
http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/4445dc89046ac1cd
>
> but now I want your advice / explanation about this thing:
>
> Imagine simple code:
>
> namespace a {
> class A { public: virtual ~A() { cout<< "~A()"; }};
> typedef A TA;
> class B : public A { public: virtual ~B() { cout<< "~B()"; }};
> }
>
> and 3 different usages:
>
> 1) This is classic usage, produces expected output: ~B()~A()
> int main() {
> char buf[100];
> a::A *p = new (buf) a::B;
> p->~A();
> }
>
This works because it finds the injected class name of the class "a::A"
(for every class definition you write, a class-name is introduced both
in the surrounding scope (that name is is a::A), and into the class
itself (that is "class a::A::A").
> 2) This doesn't compile "20:error: expected class-name before ?(?
> token".
> int main() {
> char buf[100];
> a::TA *p = new (buf) a::B;
> p->~TA(); //line 20
> }
>
When you use an unqualified name, the compiler has to know what that
name means. To allow you to use a name of the current scope (which is
often the case in templates in calls like "p->~T()" when T is a template
parameter) the name is looked up in the current scope and in the scope
of "p" separately. If at least one of these lookups finds a class-name
of the class of p, it's fine.
In this case neither scope has a "TA" defined so this fails (as far as
the Standard is concerned, "TA" which was used for defining p is just a
type alias and has no bearing on the type of p, just on how you name
it). You can make this work by providing "TA" in the surrounding scope
int main() {
char buf[100];
a::TA *p = new (buf) a::B;
using a::TA;
p->~TA();
}
I think another way is to abuse the fact that a "X<T>" is also a
class-name and can be used after "~" (note that "X<T>::type", as would
be when you would use "std::conditional<>" or "boost::identity<>", is
not a class-name but one with a qualifier before it), so you can also say
template<typename T>
using Identity = T;
int main() {
char buf[100];
a::TA *p = new (buf) a::B;
p->~Identity<a::TA>();
}
> 3) This compiles but produces unexpected output: ~A().
> I understand this because it is not "virtual" call of destructor.
> int main() {
> char buf[100];
> a::TA *p = new (buf) a::B;
> p->a::TA::~TA();
> }
>
This works because when you qualify the destructor id like
p-> qualifier :: type :: ~type
Then the last "type" name is looked up in the same scope where the first
"type" was found. So the last "TA" is not looked up in the class "a::A"
(where it would not be found), but in namespace "a" where it will be found.
I believe that your understanding is correct, this inhibits the virtual
calling since you use a qualified name.
Note that this lookup is nutoriously complicated and is subject of
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#399 (so
arguably "in the same scope where the first 'type' was found" looks a
bit simplified above but I believe it catches the common cases). If you
can I would avoid qualified constructor calls.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]