Destructor of typedef alias

Multi tool use
Clash Royale CLAN TAG#URR8PPP
up vote
20
down vote
favorite
#include <iostream>
struct A ~A(); ;
A::~A()
std::cout << "Destructor was called!" << std::endl;
typedef A AB;
int main()
AB x;
x.AB::~AB(); // Why does this work?
x.AB::~A();
The output of the above program is:
Destructor was called!
Destructor was called!
Destructor was called!
I assume the first two lines belonging to user destructor calls, while the third line is due to the destructor being called when exiting the scope of main
function.
From my understanding a typedef is an alias for a type. In this case AB
is an alias for A
.
Why does this apply for the name of the destructor too? A reference to the language specification is very much appreciated.
Edit: This was compiled using Apple LLVM version 9.1.0 (clang-902.0.39.1) on macOS High Sierra Version 10.13.3.
c++ language-lawyer destructor typedef
add a comment |Â
up vote
20
down vote
favorite
#include <iostream>
struct A ~A(); ;
A::~A()
std::cout << "Destructor was called!" << std::endl;
typedef A AB;
int main()
AB x;
x.AB::~AB(); // Why does this work?
x.AB::~A();
The output of the above program is:
Destructor was called!
Destructor was called!
Destructor was called!
I assume the first two lines belonging to user destructor calls, while the third line is due to the destructor being called when exiting the scope of main
function.
From my understanding a typedef is an alias for a type. In this case AB
is an alias for A
.
Why does this apply for the name of the destructor too? A reference to the language specification is very much appreciated.
Edit: This was compiled using Apple LLVM version 9.1.0 (clang-902.0.39.1) on macOS High Sierra Version 10.13.3.
c++ language-lawyer destructor typedef
1
That code is remarkably similar to an example in §3.4.3 in C++11.
– molbdnilo
Sep 10 at 11:45
Note that the destructor doesn't formally have a name (and neither do constructors).
– molbdnilo
Sep 10 at 11:54
@molbdnilo I wrote this example some time ago. When I remember correctly, it was inspired from an entry on cppreference, so I guess they in turn took the example from the language standard.
– Felix Crazzolara
Sep 10 at 12:45
1
Btw, you invoke UB by destroying several times the same object.
– Jarod42
Sep 10 at 13:36
add a comment |Â
up vote
20
down vote
favorite
up vote
20
down vote
favorite
#include <iostream>
struct A ~A(); ;
A::~A()
std::cout << "Destructor was called!" << std::endl;
typedef A AB;
int main()
AB x;
x.AB::~AB(); // Why does this work?
x.AB::~A();
The output of the above program is:
Destructor was called!
Destructor was called!
Destructor was called!
I assume the first two lines belonging to user destructor calls, while the third line is due to the destructor being called when exiting the scope of main
function.
From my understanding a typedef is an alias for a type. In this case AB
is an alias for A
.
Why does this apply for the name of the destructor too? A reference to the language specification is very much appreciated.
Edit: This was compiled using Apple LLVM version 9.1.0 (clang-902.0.39.1) on macOS High Sierra Version 10.13.3.
c++ language-lawyer destructor typedef
#include <iostream>
struct A ~A(); ;
A::~A()
std::cout << "Destructor was called!" << std::endl;
typedef A AB;
int main()
AB x;
x.AB::~AB(); // Why does this work?
x.AB::~A();
The output of the above program is:
Destructor was called!
Destructor was called!
Destructor was called!
I assume the first two lines belonging to user destructor calls, while the third line is due to the destructor being called when exiting the scope of main
function.
From my understanding a typedef is an alias for a type. In this case AB
is an alias for A
.
Why does this apply for the name of the destructor too? A reference to the language specification is very much appreciated.
Edit: This was compiled using Apple LLVM version 9.1.0 (clang-902.0.39.1) on macOS High Sierra Version 10.13.3.
c++ language-lawyer destructor typedef
c++ language-lawyer destructor typedef
edited Sep 10 at 11:44
P.W
3,366325
3,366325
asked Sep 10 at 11:27


Felix Crazzolara
404316
404316
1
That code is remarkably similar to an example in §3.4.3 in C++11.
– molbdnilo
Sep 10 at 11:45
Note that the destructor doesn't formally have a name (and neither do constructors).
– molbdnilo
Sep 10 at 11:54
@molbdnilo I wrote this example some time ago. When I remember correctly, it was inspired from an entry on cppreference, so I guess they in turn took the example from the language standard.
– Felix Crazzolara
Sep 10 at 12:45
1
Btw, you invoke UB by destroying several times the same object.
– Jarod42
Sep 10 at 13:36
add a comment |Â
1
That code is remarkably similar to an example in §3.4.3 in C++11.
– molbdnilo
Sep 10 at 11:45
Note that the destructor doesn't formally have a name (and neither do constructors).
– molbdnilo
Sep 10 at 11:54
@molbdnilo I wrote this example some time ago. When I remember correctly, it was inspired from an entry on cppreference, so I guess they in turn took the example from the language standard.
– Felix Crazzolara
Sep 10 at 12:45
1
Btw, you invoke UB by destroying several times the same object.
– Jarod42
Sep 10 at 13:36
1
1
That code is remarkably similar to an example in §3.4.3 in C++11.
– molbdnilo
Sep 10 at 11:45
That code is remarkably similar to an example in §3.4.3 in C++11.
– molbdnilo
Sep 10 at 11:45
Note that the destructor doesn't formally have a name (and neither do constructors).
– molbdnilo
Sep 10 at 11:54
Note that the destructor doesn't formally have a name (and neither do constructors).
– molbdnilo
Sep 10 at 11:54
@molbdnilo I wrote this example some time ago. When I remember correctly, it was inspired from an entry on cppreference, so I guess they in turn took the example from the language standard.
– Felix Crazzolara
Sep 10 at 12:45
@molbdnilo I wrote this example some time ago. When I remember correctly, it was inspired from an entry on cppreference, so I guess they in turn took the example from the language standard.
– Felix Crazzolara
Sep 10 at 12:45
1
1
Btw, you invoke UB by destroying several times the same object.
– Jarod42
Sep 10 at 13:36
Btw, you invoke UB by destroying several times the same object.
– Jarod42
Sep 10 at 13:36
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
19
down vote
accepted
Why does this apply for the name of the destructor too?
Because standard says:
[class.dtor]
In an explicit destructor call, the destructor is specified by a ~ followed by a type-name or decltype-specifier
that denotes the destructor’s class type. ...
A typedef alias is a type-name which denotes the same class as the type-name of the class itself.
The rule even has a clarifying example:
struct B
virtual ~B()
;
struct D : B
~D()
;
D D_object;
typedef B B_alias;
B* B_ptr = &D_object;
void f()
D_object.B::~B(); // calls B's destructor
B_ptr->~B(); // calls D's destructor
B_ptr->~B_alias(); // calls D's destructor
B_ptr->B_alias::~B(); // calls B's destructor
B_ptr->B_alias::~B_alias(); // calls B's destructor
Further specification about the name lookup, also with an example that applies to the question:
[basic.lookup.qual]
If a pseudo-destructor-name ([expr.pseudo]) contains a
nested-name-specifier, the type-names are looked up as types in the
scope designated by the nested-name-specifier. Similarly, in a
qualified-id of the form:
nested-name-specifieropt class-name :: ~ class-name
the second class-name is looked up in the same scope as the first.
[ Example:struct C
typedef int I;
;
typedef int I1, I2;
extern int* p;
extern int* q;
p->C::I::~I(); // I is looked up in the scope of C
q->I1::~I2(); // I2 is looked up in the scope of the postfix-expression
struct A
~A();
;
typedef A AB;
int main()
AB* p;
p->AB::~AB(); // explicitly calls the destructor for A
— end example  ]
1
... and the name is looked up in the global scope instead of the scope ofA
per [basic.lookup.qual]/6.
– xskxzr
Sep 10 at 11:52
@xskxzr thanks. I quoted that rule as well.
– user2079303
Sep 10 at 11:58
add a comment |Â
up vote
6
down vote
Because when you write ~AB()
you are not naming or calling the destructor. You are writing ~
followed by the a name of the class, and the destructor call is automatically provisioned as a result of the specified semantics of writing those tokens next to each other.
Usually this is academic but here you see why it can matter.
Similarly, by writing AB()
you are not "calling a constructor", even though this looks like a function call and many language newcomers interpret the code this way. (This can lead to fun and games when attempting to call a template constructor without argument deduction: without being able to name the constructor, there's no way to provide those arguments!)
In fact, neither the constructor nor the destructor technically even have a name!
These nuances make C++ fun, right?
(More "fun" answer to complement the thick standardese that was actually requested)
– Lightness Races in Orbit
Sep 10 at 12:23
By that metric, C++ has order-of-magntiudes more fun-per-bit than any other popular computer language.
– Eljay
Sep 10 at 12:34
2
@Eljay And that's why we love it ^_^
– Lightness Races in Orbit
Sep 10 at 13:15
I think this is not just more "fun" but also a very useful and informative answer.
– molbdnilo
Sep 10 at 13:21
@molbdnilo Well, I don't like to brag ;) (yes I do)
– Lightness Races in Orbit
Sep 10 at 13:25
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
19
down vote
accepted
Why does this apply for the name of the destructor too?
Because standard says:
[class.dtor]
In an explicit destructor call, the destructor is specified by a ~ followed by a type-name or decltype-specifier
that denotes the destructor’s class type. ...
A typedef alias is a type-name which denotes the same class as the type-name of the class itself.
The rule even has a clarifying example:
struct B
virtual ~B()
;
struct D : B
~D()
;
D D_object;
typedef B B_alias;
B* B_ptr = &D_object;
void f()
D_object.B::~B(); // calls B's destructor
B_ptr->~B(); // calls D's destructor
B_ptr->~B_alias(); // calls D's destructor
B_ptr->B_alias::~B(); // calls B's destructor
B_ptr->B_alias::~B_alias(); // calls B's destructor
Further specification about the name lookup, also with an example that applies to the question:
[basic.lookup.qual]
If a pseudo-destructor-name ([expr.pseudo]) contains a
nested-name-specifier, the type-names are looked up as types in the
scope designated by the nested-name-specifier. Similarly, in a
qualified-id of the form:
nested-name-specifieropt class-name :: ~ class-name
the second class-name is looked up in the same scope as the first.
[ Example:struct C
typedef int I;
;
typedef int I1, I2;
extern int* p;
extern int* q;
p->C::I::~I(); // I is looked up in the scope of C
q->I1::~I2(); // I2 is looked up in the scope of the postfix-expression
struct A
~A();
;
typedef A AB;
int main()
AB* p;
p->AB::~AB(); // explicitly calls the destructor for A
— end example  ]
1
... and the name is looked up in the global scope instead of the scope ofA
per [basic.lookup.qual]/6.
– xskxzr
Sep 10 at 11:52
@xskxzr thanks. I quoted that rule as well.
– user2079303
Sep 10 at 11:58
add a comment |Â
up vote
19
down vote
accepted
Why does this apply for the name of the destructor too?
Because standard says:
[class.dtor]
In an explicit destructor call, the destructor is specified by a ~ followed by a type-name or decltype-specifier
that denotes the destructor’s class type. ...
A typedef alias is a type-name which denotes the same class as the type-name of the class itself.
The rule even has a clarifying example:
struct B
virtual ~B()
;
struct D : B
~D()
;
D D_object;
typedef B B_alias;
B* B_ptr = &D_object;
void f()
D_object.B::~B(); // calls B's destructor
B_ptr->~B(); // calls D's destructor
B_ptr->~B_alias(); // calls D's destructor
B_ptr->B_alias::~B(); // calls B's destructor
B_ptr->B_alias::~B_alias(); // calls B's destructor
Further specification about the name lookup, also with an example that applies to the question:
[basic.lookup.qual]
If a pseudo-destructor-name ([expr.pseudo]) contains a
nested-name-specifier, the type-names are looked up as types in the
scope designated by the nested-name-specifier. Similarly, in a
qualified-id of the form:
nested-name-specifieropt class-name :: ~ class-name
the second class-name is looked up in the same scope as the first.
[ Example:struct C
typedef int I;
;
typedef int I1, I2;
extern int* p;
extern int* q;
p->C::I::~I(); // I is looked up in the scope of C
q->I1::~I2(); // I2 is looked up in the scope of the postfix-expression
struct A
~A();
;
typedef A AB;
int main()
AB* p;
p->AB::~AB(); // explicitly calls the destructor for A
— end example  ]
1
... and the name is looked up in the global scope instead of the scope ofA
per [basic.lookup.qual]/6.
– xskxzr
Sep 10 at 11:52
@xskxzr thanks. I quoted that rule as well.
– user2079303
Sep 10 at 11:58
add a comment |Â
up vote
19
down vote
accepted
up vote
19
down vote
accepted
Why does this apply for the name of the destructor too?
Because standard says:
[class.dtor]
In an explicit destructor call, the destructor is specified by a ~ followed by a type-name or decltype-specifier
that denotes the destructor’s class type. ...
A typedef alias is a type-name which denotes the same class as the type-name of the class itself.
The rule even has a clarifying example:
struct B
virtual ~B()
;
struct D : B
~D()
;
D D_object;
typedef B B_alias;
B* B_ptr = &D_object;
void f()
D_object.B::~B(); // calls B's destructor
B_ptr->~B(); // calls D's destructor
B_ptr->~B_alias(); // calls D's destructor
B_ptr->B_alias::~B(); // calls B's destructor
B_ptr->B_alias::~B_alias(); // calls B's destructor
Further specification about the name lookup, also with an example that applies to the question:
[basic.lookup.qual]
If a pseudo-destructor-name ([expr.pseudo]) contains a
nested-name-specifier, the type-names are looked up as types in the
scope designated by the nested-name-specifier. Similarly, in a
qualified-id of the form:
nested-name-specifieropt class-name :: ~ class-name
the second class-name is looked up in the same scope as the first.
[ Example:struct C
typedef int I;
;
typedef int I1, I2;
extern int* p;
extern int* q;
p->C::I::~I(); // I is looked up in the scope of C
q->I1::~I2(); // I2 is looked up in the scope of the postfix-expression
struct A
~A();
;
typedef A AB;
int main()
AB* p;
p->AB::~AB(); // explicitly calls the destructor for A
— end example  ]
Why does this apply for the name of the destructor too?
Because standard says:
[class.dtor]
In an explicit destructor call, the destructor is specified by a ~ followed by a type-name or decltype-specifier
that denotes the destructor’s class type. ...
A typedef alias is a type-name which denotes the same class as the type-name of the class itself.
The rule even has a clarifying example:
struct B
virtual ~B()
;
struct D : B
~D()
;
D D_object;
typedef B B_alias;
B* B_ptr = &D_object;
void f()
D_object.B::~B(); // calls B's destructor
B_ptr->~B(); // calls D's destructor
B_ptr->~B_alias(); // calls D's destructor
B_ptr->B_alias::~B(); // calls B's destructor
B_ptr->B_alias::~B_alias(); // calls B's destructor
Further specification about the name lookup, also with an example that applies to the question:
[basic.lookup.qual]
If a pseudo-destructor-name ([expr.pseudo]) contains a
nested-name-specifier, the type-names are looked up as types in the
scope designated by the nested-name-specifier. Similarly, in a
qualified-id of the form:
nested-name-specifieropt class-name :: ~ class-name
the second class-name is looked up in the same scope as the first.
[ Example:struct C
typedef int I;
;
typedef int I1, I2;
extern int* p;
extern int* q;
p->C::I::~I(); // I is looked up in the scope of C
q->I1::~I2(); // I2 is looked up in the scope of the postfix-expression
struct A
~A();
;
typedef A AB;
int main()
AB* p;
p->AB::~AB(); // explicitly calls the destructor for A
— end example  ]
edited Sep 10 at 11:58
answered Sep 10 at 11:44
user2079303
69.2k550109
69.2k550109
1
... and the name is looked up in the global scope instead of the scope ofA
per [basic.lookup.qual]/6.
– xskxzr
Sep 10 at 11:52
@xskxzr thanks. I quoted that rule as well.
– user2079303
Sep 10 at 11:58
add a comment |Â
1
... and the name is looked up in the global scope instead of the scope ofA
per [basic.lookup.qual]/6.
– xskxzr
Sep 10 at 11:52
@xskxzr thanks. I quoted that rule as well.
– user2079303
Sep 10 at 11:58
1
1
... and the name is looked up in the global scope instead of the scope of
A
per [basic.lookup.qual]/6.– xskxzr
Sep 10 at 11:52
... and the name is looked up in the global scope instead of the scope of
A
per [basic.lookup.qual]/6.– xskxzr
Sep 10 at 11:52
@xskxzr thanks. I quoted that rule as well.
– user2079303
Sep 10 at 11:58
@xskxzr thanks. I quoted that rule as well.
– user2079303
Sep 10 at 11:58
add a comment |Â
up vote
6
down vote
Because when you write ~AB()
you are not naming or calling the destructor. You are writing ~
followed by the a name of the class, and the destructor call is automatically provisioned as a result of the specified semantics of writing those tokens next to each other.
Usually this is academic but here you see why it can matter.
Similarly, by writing AB()
you are not "calling a constructor", even though this looks like a function call and many language newcomers interpret the code this way. (This can lead to fun and games when attempting to call a template constructor without argument deduction: without being able to name the constructor, there's no way to provide those arguments!)
In fact, neither the constructor nor the destructor technically even have a name!
These nuances make C++ fun, right?
(More "fun" answer to complement the thick standardese that was actually requested)
– Lightness Races in Orbit
Sep 10 at 12:23
By that metric, C++ has order-of-magntiudes more fun-per-bit than any other popular computer language.
– Eljay
Sep 10 at 12:34
2
@Eljay And that's why we love it ^_^
– Lightness Races in Orbit
Sep 10 at 13:15
I think this is not just more "fun" but also a very useful and informative answer.
– molbdnilo
Sep 10 at 13:21
@molbdnilo Well, I don't like to brag ;) (yes I do)
– Lightness Races in Orbit
Sep 10 at 13:25
add a comment |Â
up vote
6
down vote
Because when you write ~AB()
you are not naming or calling the destructor. You are writing ~
followed by the a name of the class, and the destructor call is automatically provisioned as a result of the specified semantics of writing those tokens next to each other.
Usually this is academic but here you see why it can matter.
Similarly, by writing AB()
you are not "calling a constructor", even though this looks like a function call and many language newcomers interpret the code this way. (This can lead to fun and games when attempting to call a template constructor without argument deduction: without being able to name the constructor, there's no way to provide those arguments!)
In fact, neither the constructor nor the destructor technically even have a name!
These nuances make C++ fun, right?
(More "fun" answer to complement the thick standardese that was actually requested)
– Lightness Races in Orbit
Sep 10 at 12:23
By that metric, C++ has order-of-magntiudes more fun-per-bit than any other popular computer language.
– Eljay
Sep 10 at 12:34
2
@Eljay And that's why we love it ^_^
– Lightness Races in Orbit
Sep 10 at 13:15
I think this is not just more "fun" but also a very useful and informative answer.
– molbdnilo
Sep 10 at 13:21
@molbdnilo Well, I don't like to brag ;) (yes I do)
– Lightness Races in Orbit
Sep 10 at 13:25
add a comment |Â
up vote
6
down vote
up vote
6
down vote
Because when you write ~AB()
you are not naming or calling the destructor. You are writing ~
followed by the a name of the class, and the destructor call is automatically provisioned as a result of the specified semantics of writing those tokens next to each other.
Usually this is academic but here you see why it can matter.
Similarly, by writing AB()
you are not "calling a constructor", even though this looks like a function call and many language newcomers interpret the code this way. (This can lead to fun and games when attempting to call a template constructor without argument deduction: without being able to name the constructor, there's no way to provide those arguments!)
In fact, neither the constructor nor the destructor technically even have a name!
These nuances make C++ fun, right?
Because when you write ~AB()
you are not naming or calling the destructor. You are writing ~
followed by the a name of the class, and the destructor call is automatically provisioned as a result of the specified semantics of writing those tokens next to each other.
Usually this is academic but here you see why it can matter.
Similarly, by writing AB()
you are not "calling a constructor", even though this looks like a function call and many language newcomers interpret the code this way. (This can lead to fun and games when attempting to call a template constructor without argument deduction: without being able to name the constructor, there's no way to provide those arguments!)
In fact, neither the constructor nor the destructor technically even have a name!
These nuances make C++ fun, right?
answered Sep 10 at 12:20


Lightness Races in Orbit
271k48436747
271k48436747
(More "fun" answer to complement the thick standardese that was actually requested)
– Lightness Races in Orbit
Sep 10 at 12:23
By that metric, C++ has order-of-magntiudes more fun-per-bit than any other popular computer language.
– Eljay
Sep 10 at 12:34
2
@Eljay And that's why we love it ^_^
– Lightness Races in Orbit
Sep 10 at 13:15
I think this is not just more "fun" but also a very useful and informative answer.
– molbdnilo
Sep 10 at 13:21
@molbdnilo Well, I don't like to brag ;) (yes I do)
– Lightness Races in Orbit
Sep 10 at 13:25
add a comment |Â
(More "fun" answer to complement the thick standardese that was actually requested)
– Lightness Races in Orbit
Sep 10 at 12:23
By that metric, C++ has order-of-magntiudes more fun-per-bit than any other popular computer language.
– Eljay
Sep 10 at 12:34
2
@Eljay And that's why we love it ^_^
– Lightness Races in Orbit
Sep 10 at 13:15
I think this is not just more "fun" but also a very useful and informative answer.
– molbdnilo
Sep 10 at 13:21
@molbdnilo Well, I don't like to brag ;) (yes I do)
– Lightness Races in Orbit
Sep 10 at 13:25
(More "fun" answer to complement the thick standardese that was actually requested)
– Lightness Races in Orbit
Sep 10 at 12:23
(More "fun" answer to complement the thick standardese that was actually requested)
– Lightness Races in Orbit
Sep 10 at 12:23
By that metric, C++ has order-of-magntiudes more fun-per-bit than any other popular computer language.
– Eljay
Sep 10 at 12:34
By that metric, C++ has order-of-magntiudes more fun-per-bit than any other popular computer language.
– Eljay
Sep 10 at 12:34
2
2
@Eljay And that's why we love it ^_^
– Lightness Races in Orbit
Sep 10 at 13:15
@Eljay And that's why we love it ^_^
– Lightness Races in Orbit
Sep 10 at 13:15
I think this is not just more "fun" but also a very useful and informative answer.
– molbdnilo
Sep 10 at 13:21
I think this is not just more "fun" but also a very useful and informative answer.
– molbdnilo
Sep 10 at 13:21
@molbdnilo Well, I don't like to brag ;) (yes I do)
– Lightness Races in Orbit
Sep 10 at 13:25
@molbdnilo Well, I don't like to brag ;) (yes I do)
– Lightness Races in Orbit
Sep 10 at 13:25
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52256851%2fdestructor-of-typedef-alias%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
That code is remarkably similar to an example in §3.4.3 in C++11.
– molbdnilo
Sep 10 at 11:45
Note that the destructor doesn't formally have a name (and neither do constructors).
– molbdnilo
Sep 10 at 11:54
@molbdnilo I wrote this example some time ago. When I remember correctly, it was inspired from an entry on cppreference, so I guess they in turn took the example from the language standard.
– Felix Crazzolara
Sep 10 at 12:45
1
Btw, you invoke UB by destroying several times the same object.
– Jarod42
Sep 10 at 13:36