Title
call_once() shouldn't DECAY_COPY()
Status
c++17
Section
[thread.once.callonce]
Submitter
Stephan T. Lavavej

Created on 2014-10-01.00:00:00 last changed 81 months ago

Messages

Date: 2015-05-22.19:14:31

Proposed resolution:

This wording is relative to N3936.

  1. Change [thread.once.callonce] p1+p2 as depicted:

    template<class Callable, class ...Args>
      void call_once(once_flag& flag, Callable&& func, Args&&... args);
    

    -1- Requires: Callable and each Ti in Args shall satisfy the MoveConstructible requirements. INVOKE(DECAY_COPY(std::forward<Callable>(func)), DECAY_COPY(std::forward<Args>(args))...) (20.9.2) shall be a valid expression.

    -2- Effects; […] An active execution shall call INVOKE(DECAY_COPY(std::forward<Callable>(func)), DECAY_COPY(std::forward<Args>(args))...). […]

Date: 2015-05-07.00:00:00

[ 2015-05-07 Lenexa: Move Immediate ]

LWG 2442 call_once shouldn't decay_copy

STL summarizes the SG1 minutes.

Marshall: Jonathan updated all the issues with SG1 status last night. Except this one.

STL summarizes the issue.

Dietmar: Of course, call_once has become useless.

STL: With magic statics.

Jonathan: Magic statics can't be per object, which I use in future.

Marshall: I see why you are removing the MoveConstructible on the arguments, but what about Callable?

STL: That's a type named Callable, which we will no longer decay_copy. We're still requiring the INVOKE expression to be valid.

Marshall: Okay. Basically, ripping the decay_copy out of here.

STL: I recall searching the Standard for other occurrences and I believe this is the only inappropriate use of decay_copy.

Marshall: We do the decay_copy.

Jonathan: Us too.

Marshall: What do people think?

Jonathan: I think STL's right. In the use I was mentioning inside futures, I actually pass them by reference_wrapper and pointers, to avoid the decay causing problems. Inside the call_once, I then extract the args. So I've had to work around this and didn't realize it was a defect.

Marshall: What do people think is the right resolution?

STL: I would like to see Immediate.

Hwrd: No objections to Immediate.

Marshall: Bill is nodding.

PJP: He said it. Everything STL says applies to our other customers.

Marshall: Any objections to Immediate?

Jonathan: I can't see any funky implementations where a decay_copy would be necessary?

Marshall: 6 votes for Immediate, 0 opposed, 0 abstaining.

Date: 2015-05-08.04:23:26

[ 2015-05 Lenexa, SG1 response ]

Looks good to us, but this is really an LWG issue.

Date: 2015-04-04.16:45:17

[ 2015-02 Cologne ]

Handed over to SG1.

Date: 2014-10-01.00:00:00

When LWG 891 overhauled call_once()'s specification, it used decay_copy(), following LWG 929's overhaul of thread's constructor.

In thread's constructor, this is necessary and critically important. [thread.thread.constr]/5 "The new thread of execution executes INVOKE(DECAY_COPY(std::forward<F>(f)), DECAY_COPY(std::forward<Args>(args))...) with the calls to DECAY_COPY being evaluated in the constructing thread." requires the parent thread to copy arguments for the child thread to access.

In call_once(), this is unnecessary and harmful. It's unnecessary because call_once() doesn't transfer arguments between threads. It's harmful because:

  • decay_copy() returns a prvalue. Given meow(int&), meow(i) can be called directly, but call_once(flag, meow, i) won't compile.

  • decay_copy() moves from modifiable rvalues. Given purr(const unique_ptr<int>&), purr(move(up)) won't modify up. (This is observable, because moved-from unique_ptrs are guaranteed empty.) However, call_once(flag, purr, move(up)) will leave up empty after the first active execution. Observe the behavioral difference — if purr() is directly called like this repeatedly until it doesn't throw an exception, each call will observe up unchanged. With call_once(), the second active execution will observe up to be empty.

call_once() should use perfect forwarding without decay_copy(), in order to avoid interfering with the call like this.

History
Date User Action Args
2017-07-30 20:15:43adminsetstatus: wp -> c++17
2015-05-22 19:14:31adminsetmessages: + msg7437
2015-05-22 18:31:21adminsetstatus: immediate -> wp
2015-05-08 22:31:48adminsetstatus: open -> immediate
2015-05-08 04:23:26adminsetmessages: + msg7402
2015-04-04 16:45:17adminsetmessages: + msg7339
2015-04-04 16:45:17adminsetstatus: new -> open
2014-10-08 20:15:09adminsetmessages: + msg7143
2014-10-01 00:00:00admincreate