https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125220

            Bug ID: 125220
           Summary: std::priority_queue move constructs twice and move
                    assigns upon emplace
           Product: gcc
           Version: 16.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ted at lyncon dot se
  Target Milestone: ---

This test program shows the one construction I would expect plus two move
constructions and a final move assignment when using `priority_queue::emplace`:
```
#include <iostream>
#include <queue>
#include <utility>

class foo {
   public:
    foo(int x) : id(++idcount), value(x) {
        ++alive;
        std::cout << "foo(int)\t\t" << *this << '\n';
    }
    foo(const foo& rhs) : id(++idcount), value(rhs.value) {
        ++alive;
        std::cout << "foo(const foo&)\t\t" << *this << " <= " << rhs << '\n';
    }
    foo(foo&& rhs) noexcept
        : id(++idcount), value(std::exchange(rhs.value, -rhs.value)) {
        ++alive;
        std::cout << "foo(foo&&)\t\t" << *this << " <= " << rhs << '\n';
    }
    foo& operator=(const foo& rhs) {
        std::cout << "foo& operator=(const foo&)\t" << *this << " <= " << rhs
<< '\n';
        value = rhs.value;
        return *this;
    }
    foo& operator=(foo&& rhs) noexcept {
        value = std::exchange(rhs.value, -rhs.value);
        std::cout << "foo& operator=(foo&&)\t" << *this << " <= " << rhs <<
'\n';
        return *this;
    }
    ~foo() {
        std::cout << "~foo()\t\t\t" << *this << '\n';
        --alive;
    }
    friend std::ostream& operator<<(std::ostream& os, const foo& f) {
        return os << R"aw({"id": )aw" << f.id << R"aw(, "value": )aw" <<
f.value << "}";
    }

    bool operator<(const foo& rhs) const { return id < rhs.id; }

   private:
    unsigned id;
    int value;
    inline static unsigned alive = 0;
    inline static unsigned idcount = 0;
};

int main() {
    std::priority_queue<foo> pq;
    pq.emplace(999);
    std::cout << "--------------------------------\n";
}
```
Output:
```
foo(int)                {"id": 1, "value": 999}
foo(foo&&)              {"id": 2, "value": 999} <= {"id": 1, "value": -999}
foo(foo&&)              {"id": 3, "value": 999} <= {"id": 2, "value": -999}
foo& operator=(foo&&)   {"id": 1, "value": 999} <= {"id": 3, "value": -999}
~foo()                  {"id": 3, "value": -999}
~foo()                  {"id": 2, "value": -999}
--------------------------------
~foo()                  {"id": 1, "value": 999}
```

The expected output (seen in MSVC and libc++):
```
foo(int)                {"id": 1, "value": 999}
--------------------------------
~foo()                  {"id": 1, "value": 999}
```

Reply via email to