Discussion Thread: DIP 1040--Copying, Moving, and Forwarding--Community Review Round 1
Walter Bright
newshound2 at digitalmars.com
Thu Mar 18 09:39:22 UTC 2021
On 3/8/2021 5:21 AM, RazvanN wrote:
> On Monday, 8 March 2021 at 10:38:25 UTC, Walter Bright wrote:
>> On 3/8/2021 12:23 AM, RazvanN wrote:
>>> On Friday, 5 March 2021 at 12:19:54 UTC, Mike Parker wrote:
>>>>
>
>>> Moreover, what happens in this case if we have a struct that's not an EMO,
>>> but defines a move constructor?
>>
>> That means it does not have a Move Assignment Operator. It doesn't get EMO
>> semantics. The Move Constructor section applies.
>>
> Even if the move assignment operator is implicitly generated? The DIP states:
> "If a Move Assignment Operator is not defined for a struct that has a Move
> constructor, a default Move Assignment Operator is defined and implemented as a
> move for each of its fields, in lexical order."
>
> Is it possible to have a non-EMO struct that defines solely a move constructor
> or solely a move assignment operator? It seems like if you define one, you
> implicitly get the other one.
That's a good point. Perhaps it should be an error to define only one.
>>> 2. What are the situations where a move constructor call is implicitly
>>> inserted by compiler? This is not explicitly stated in the DIP and it is
>>> rather confusing.
>>
>> It's in the Move Constructor section.
>>
>>
>>> For example, when an instance is passed by `move ref` is there a move
>>> constructor call?
>>
>> No, because it is passed by ref.
> Ok, correct me if I am wrong, but it seems that if you define a move
> constructor, you implicitly get a move assignment operator and viceversa. This
> means that your struct becomes an EMO if you define one or the other. Once you
> have an EMO struct, besides the trivial `S a = b` are there any other situations
> where the move constructor may be called?
void g(S b) {
S a = b; // calls copy constructor (not last use of b)
S c = b; // calls move constructor (last use of b)
}
It seems that EMOs are always passed
> by reference. If that is the case, why bother defining a move constructor when
> it will not get called? If I am mistaken, can you please provide a non-trivial
> example where the move constructor gets called?
void f(S s);
void g(S a) {
f(a); // copy constructor called because not last use of `a`
f(a); // move constructor called because last use of `a`
}
>>> 3. The DIP should explicitly state what happens when you pass an rvalue
>>> instance of an EMO by ref. How does that interact with
>>> `-preview=rvaluerefparam` ?
>>
>> With EMOs, there is no need to use the 'ref' annotation. If you do use 'ref',
>> the special EMO semantics do not apply.
>>
> So I assume you get an error?
No, it just works the way it does now.
> Also, what happens with `auto ref` deduction when
> called with an EMO.
Auto ref parameters are only for template functions. "An auto ref function
template parameter becomes a ref parameter if its corresponding argument is an
lvalue, otherwise it becomes a value parameter"
https://dlang.org/spec/template.html#auto-ref-parameters
It will continue to do exactly what it says.
> The DIP has this example:
>
> ref S fwd(return ref S s) { return s; }
>
> void f(S s);
> ...
> S s;
> f(fwd(s));
> f(fwd(S());
>
> Assuming S is an EMO, when we have `f(fwd(S()))` what happens here? Is a
> reference to the rvalue passed to `fwd` or does the move constructor get called?
> If we simply call `f(S())`, what happens here? Is `S()` passed by move ref or do
> we have a move constructor call?
>
> The DIP talks about move refs, but the examples only use lvalues. Is the move
> constructor ever called for an rvalue instance of an EMO?
What happens is just what the spec says:
"Ownership of the argument to fwd() is retained by the caller, and so the caller
will be responsible for its destruction. When the call is made to f(), a copy is
made."
No move copies or move assignments are done. BUT, if the compiler can look
inside the fwd() function, it can see that `s` can be moved directly to `f` in
the first case, and `S()` can be moved directly to `f` in the second. Thus, here
the move constructor is used as an optimization.
More information about the Digitalmars-d
mailing list