8

Is there a reason (other than because the standard says so) to why the following code is not allowed?

struct Foo
{
    ~Foo() && {}
    ~Foo() & {}
};

I know that it is illegal, but I wanna know why.

I was thinking about the good old avoid unnamed instances problem, i.e. when using guard objects, like:

void do_something()
{
    std::lock_guard{my_mutex};
    // some synchronized operation
}

This is legal code but obviously error prone since the lock guard would be destroyed immediately after its construction, because it's a temporary (unnamed) object.

I was planning on doing something like this

struct Foo
{
    ~Foo() && = delete;
    ~Foo() & = default;
};

and get a compiler error if the type is constructed as a temporary.

Timo
  • 9,269
  • 2
  • 28
  • 58
  • 6
    What should be the purpose of the reference qualifiers there? – t.niese Feb 28 '20 at 08:31
  • 1
    What is a kind of requirement you have? – Build Succeeded Feb 28 '20 at 08:33
  • 2
    I would say, because a destructor destroys the object. There is no reason why it should have any qualifiers. A referenced object is never destroyed. What would you do with a class using those qualifiers? – Gerhard Stein Feb 28 '20 at 08:34
  • @t.niese I was thinking about ways to avoid unnamed instances. I know reference qualifiers aren't a perfect solution to this either but I figured it'd be better than nothing. – Timo Feb 28 '20 at 09:01
  • 1
    @Dr.-Ing.GerhardStein Not sure what you mean by _"A referenced object is never destroyed"_. That's where dangling references come from. – Timo Feb 28 '20 at 09:03
  • @Mannoj no requirements, just theory crafting. – Timo Feb 28 '20 at 09:04
  • @Timo I still don't see what problem this should solve. Could you probably extend your question with an example that would illustrate where this would help? – t.niese Feb 28 '20 at 09:09
  • @Timo Hmm, dangling references. Well, can you give us an example where you would use your class. I think it might clarify what you are trying to achieve. – Gerhard Stein Feb 28 '20 at 09:11
  • 1
    Without having the same for constructors, I don't really see the point having this. – geza Feb 28 '20 at 09:11
  • 1
    @t.niese Added an example – Timo Feb 28 '20 at 09:28
  • @geza Indeed the constructor could also be used for my purposes, haven't thought about that. – Timo Feb 28 '20 at 09:30
  • Yes, or maybe there is some other way to do this. So, maybe it would have been better to ask "how to have a warning, if lock_guards are used as temporaries", instead of asking this question (if you have this specific problem in mind). – geza Feb 28 '20 at 11:13
  • @geza Yeah I just had a conversation on the cpp slack channel about this. Turns out we can use `[[nodiscard]]` on ctors now which gives us a warning. If we could make `nodiscard` a keyword, that would be pretty awesome to avoid missuse of guard types imo. – Timo Feb 28 '20 at 11:54

1 Answers1

4

First, there must be only one destructor per class. Allowing ref-qualifiers on the destructor would make it possible to overload the destructor.

Another possible reason is to be consistent with const and volatile qualifiers:

A destructor shall not be declared const, volatile or const volatile (9.3.2). const and volatile semantics (7.1.5.1) are not applied on an object under destruction.

I guess, for consistency, distinguishing between rvalues and lvalues is not applied on an object under destruction.

JFMR
  • 23,265
  • 4
  • 52
  • 76
  • 1
    Interesting, would a change in that behavior (if we were to allow reference qualifiers) affect existing code? – Timo Feb 28 '20 at 09:34
  • This is just a "because the standard says so" answer, doesn't really answer the why. Of course, if we had `&` and `&&` destructors, it means overloading the destructor. This is the question about. – geza Feb 28 '20 at 09:35
  • 1
    @Timo I think it would be backwards compatible since the existing code doesn't use it. – JFMR Feb 28 '20 at 10:12