Bug 72580 - Cannot throw non movable object
Summary: Cannot throw non movable object
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-07-26 10:35 UTC by Gleb Natapov
Modified: 2016-07-26 12:06 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Gleb Natapov 2016-07-26 10:35:28 UTC
This program fails to compile with "xx.cc:12:11: error: use of deleted function ‘E::E(E&&)’" error. It should use copy constructor instead.

struct E {
    int x;
    E(int x_) : x(x_) {}
    ~E() {}
    E(E&&) = delete;
    E(const E& o) : x(o.x) {}
    E& operator=(const E& o) { x = o.x; return *this; }
};

int main() {
    E ex(1);
    throw ex;
}
Comment 1 Jonathan Wakely 2016-07-26 10:58:58 UTC
The copy is eligible for elision, which means lookup is performed as if 'ex' was an rvalue. That lookup finds a deleted constructor, so you get an error.

[except.throw] p5 specifically says the constructor must be non-deleted:

  When the thrown object is a class object, the constructor selected for the
  copy-initialization as well as the constructor selected for a 
  copy-initialization considering the thrown object as an lvalue shall be
  non-deleted and accessible, even if the copy/move operation is elided (12.8).

Don't delete move constructors, it doesn't make sense.
Comment 2 Gleb Natapov 2016-07-26 11:36:08 UTC
As far as I see it talks about copy constructor not move constructor. Clang compiles the code just fine.
Comment 3 Jonathan Wakely 2016-07-26 11:40:07 UTC
(In reply to Gleb Natapov from comment #2)
> As far as I see it talks about copy constructor not move constructor.

No, it says "the constructor" not "the copy constructor".

Copy initialization refers to the syntactic form of initialization, not whether it uses a copy constructor or a move constructor.

It also specifically talks about "the copy/move operation".



> Clang
> compiles the code just fine.

And Intel icc rejects it for using a deleted function.
Comment 4 Gleb Natapov 2016-07-26 11:56:35 UTC
(In reply to Jonathan Wakely from comment #3)
> (In reply to Gleb Natapov from comment #2)
> > As far as I see it talks about copy constructor not move constructor.
> 
> No, it says "the constructor" not "the copy constructor".
> 
> Copy initialization refers to the syntactic form of initialization, not
> whether it uses a copy constructor or a move constructor.
> 
> It also specifically talks about "the copy/move operation".
Spec talks about "the constructor selected for the copy-initialization". In my example throw gets lvalue object, so the object should be copied but the copy is elided. If I made object const the code compiles since copy cannot be elided. If I would throw E(1) then it would elide move indeed.

Not that I doubt your reading of the spec, you are obviously more experienced in this (and Intel agrees with you), but I would like to understand it better.
Comment 5 Jonathan Wakely 2016-07-26 12:06:11 UTC
Please stop changing the resolution to FIXED!

The relevant rule is [class.copy] p32 in C++14 but this is not the right place to learn C++, try somewhere like stackoverflow.