This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++20 status.

### 3334. `basic_osyncstream` move assignment and destruction calls `basic_syncbuf::emit()` twice

Section: 31.11.3 [syncstream.osyncstream] Status: C++20 Submitter: Tim Song Opened: 2019-11-06 Last modified: 2021-02-25

Priority: 3

View all issues with C++20 status.

Discussion:

These functions are specified to call `emit()`, which calls `emit()` on the `basic_syncbuf` and sets `badbit` if it fails. Then, the move assignment is specified to move-assign the `basic_syncbuf`, while the destructor implicitly needs to destroy the `basic_syncbuf` data member. This calls `emit()` on the `basic_syncbuf` again.

Is this intended?

[2020-02-13 Tim adds wording after discussion with Peter]

[2020-02 Status to Immediate Thursday afternoon in Prague.]

Proposed resolution:

This wording is relative to N4849.

> [Drafting note: There is no need to explicitly call `emit` at all in these functions; memberwise move-assignment/destruction is sufficient, so we can strike the specification entirely and rely on the wording in 16.3.3.4 [functions.within.classes]. — end drafting note]

1. Edit 31.11.3.2 [syncstream.osyncstream.cons] as indicated:

   >     ~basic_osyncstream();

   > > -6- Effects: Calls `emit()`. If an exception is thrown from `emit()`, that exception is caught and ignored.

2. Strike [syncstream.osyncstream.assign]:

   >     basic_osyncstream& operator=(basic_osyncstream&& rhs) noexcept;

   > > -1- Effects: First, calls `emit()`. If an exception is thrown from `emit()`, that exception is caught and ignored. Move assigns `sb` from `rhs.sb`. [ Note: This disassociates `rhs` from its wrapped stream buffer ensuring destruction of `rhs` produces no output. — end note ]

   > > -2- Postconditions: `nullptr == rhs.get_wrapped()` is `true`. `get_wrapped()` returns the value previously returned by `rhs.get_wrapped()`.