Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
December 13, 2018 Can you move a disabled this(this) struct in to a container type if it's an rvalue? | ||||
---|---|---|---|---|
| ||||
Ie: struct S { @disable this(this); this(int i) {} } struct Container(T) { T value; this(T value) { this.value = value; } } void main() { auto a = Container!S(S(3)); // can't do this. } I can build a custom constructor for Container that makes this work: static auto construct(Args...)(auto ref Args args) { import std.algorithm: move; auto value = T(args); auto opt = Container!T.init; opt.value = move(value); return move(opt); } And then "auto a = Container!T.construct(3);" works. But is there a way to do it without adding a custom constructor type? Cheers, - Ali |
December 13, 2018 Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue? | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | On Thursday, 13 December 2018 at 09:51:42 UTC, aliak wrote:
> Ie:
>
> struct S {
> @disable this(this);
> this(int i) {}
> }
>
> struct Container(T) {
> T value;
> this(T value) {
> this.value = value;
> }
> }
>
> void main() {
> auto a = Container!S(S(3)); // can't do this.
> }
>
> I can build a custom constructor for Container that makes this work:
>
> static auto construct(Args...)(auto ref Args args) {
> import std.algorithm: move;
> auto value = T(args);
> auto opt = Container!T.init;
> opt.value = move(value);
> return move(opt);
> }
>
> And then "auto a = Container!T.construct(3);" works.
>
> But is there a way to do it without adding a custom constructor type?
>
> Cheers,
> - Ali
You can just move in container constructor:
struct S {
@disable this(this);
this(int i) {}
}
struct Container(T) {
T value;
this(T value) {
import std.algorithm: move;
this.value = value.move;
}
}
void main() {
auto a = Container!S(S(3));
}
|
December 13, 2018 Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Boris-Barboris | On Thursday, 13 December 2018 at 12:08:22 UTC, Boris-Barboris wrote:
> On Thursday, 13 December 2018 at 09:51:42 UTC, aliak wrote:
>> [...]
>
>
> You can just move in container constructor:
>
>
> struct S {
> @disable this(this);
> this(int i) {}
> }
>
> struct Container(T) {
> T value;
> this(T value) {
> import std.algorithm: move;
> this.value = value.move;
> }
> }
>
> void main() {
> auto a = Container!S(S(3));
> }
Ah. Is there any case where you would not want to do that when you have a T value as parameter?
And, what if it's "this()(auto ref T value)"? Then moving could be dangerous if the parameter was passed as a ref. Or maybe it just wouldn't compile?
|
December 13, 2018 Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue? | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | On 12/13/18 8:17 AM, aliak wrote: > On Thursday, 13 December 2018 at 12:08:22 UTC, Boris-Barboris wrote: >> On Thursday, 13 December 2018 at 09:51:42 UTC, aliak wrote: >>> [...] >> >> >> You can just move in container constructor: >> >> >> struct S { >> @disable this(this); >> this(int i) {} >> } >> >> struct Container(T) { >> T value; >> this(T value) { >> import std.algorithm: move; >> this.value = value.move; >> } >> } >> >> void main() { >> auto a = Container!S(S(3)); >> } > > Ah. Is there any case where you would not want to do that when you have a T value as parameter? Probably not an issue. Note that if you take the parameter by value, the T must be an rvalue if it has disabled postblit. In other words, this wouldn't work: S s; auto a = Container!S(s); // error So moving it isn't going to affect anything outside the function. > > And, what if it's "this()(auto ref T value)"? Then moving could be dangerous if the parameter was passed as a ref. Or maybe it just wouldn't compile? What will happen is then you *could* take an already existing T as a parameter, and the T you pass in will be destroyed upon calling the constructor. move resets the original to the .init value if it has a destructor or postblit. Is it dangerous? Probably not, but you may want to document for anyone who uses the container to expect that. -Steve |
December 13, 2018 Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue? | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | On Thursday, 13 December 2018 at 13:17:05 UTC, aliak wrote: > > Ah. Is there any case where you would not want to do that when you have a T value as parameter? > > And, what if it's "this()(auto ref T value)"? Then moving could be dangerous if the parameter was passed as a ref. Or maybe it just wouldn't compile? Here's a version that moves rvalues and either copies lvalues, or fails to compile if it can't: struct Container(T) { T value; this(T value) { import std.algorithm.mutation : move; this.value = move(value); } import std.traits : isCopyable; static if (isCopyable!T) { this(ref T value) { this.value = value; } } } Full example: https://run.dlang.io/is/0dw6zz |
December 13, 2018 Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue? | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | On Thursday, 13 December 2018 at 13:17:05 UTC, aliak wrote: > Ah. Is there any case where you would not want to do that when you have a T value as parameter? Hypothetically, yes, e.g. an object that contains references to itself. However, D operates on the assumption that you don't have such objects. And even though it can't be statically checked, move and swap do actually perform this check at runtime in debug builds. Operating under that rule, it should be legal to move any values that are passed to you. In fact, I postulate that it *must* be done instead of making copies. Unfortunately, Phobos doesn't agree. struct S { int x; this(this) { x++; } } import std.stdio; writeln(S.init); I would expect that to print S(0). However, it doesn't, which is sad. > And, what if it's "this()(auto ref T value)"? Then moving could be dangerous if the parameter was passed as a ref. Or maybe it just wouldn't compile? In that case moving indeed could be dangerous since you'd be modifying caller's state. A workaround is indeed to have different signatures or use `auto ref`. The constructor example in this thread doesn't fully address the difference between copying and moving though, because it's dealing with initialization. A more practical example is an actual container, like an array (simplified for brevity): struct Array(T) { T[] memory; size_t size; void append()(auto ref T x) { static if (__traits(isRef, x)) { import std.conv : emplace; // copy-construct. Note that this is different than doing // memory[size++] = x; // because that will call opAssign instead of initializing + postblit emplace(&memory[size++], x); } else { import std.algorithm.mutation : moveEmplace; moveEmplace(x, memory[size++]); } } } That's different from the example being discussed, since assignment inside a constructor gets special treatment: struct Container(T) { T data; this()(auto ref T x) { static if (__traits(isRef, x)) data = x; // this assignment is initialization, so emplace is not needed, copy is being made else moveEmplace(x, data); } } |
December 15, 2018 Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stanislav Blinov | On Thursday, 13 December 2018 at 23:33:39 UTC, Stanislav Blinov wrote:
> On Thursday, 13 December 2018 at 13:17:05 UTC, aliak wrote:
>
>> [...]
>
> Hypothetically, yes, e.g. an object that contains references to itself. However, D operates on the assumption that you don't have such objects. And even though it can't be statically checked, move and swap do actually perform this check at runtime in debug builds.
> Operating under that rule, it should be legal to move any values that are passed to you. In fact, I postulate that it *must* be done instead of making copies. Unfortunately, Phobos doesn't agree.
>
> [...]
Oh cool! An isRef trait. TIL!
And I see, thank you all for the tips!
|
December 16, 2018 Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stanislav Blinov | On Thursday, 13 December 2018 at 23:33:39 UTC, Stanislav Blinov wrote: > On Thursday, 13 December 2018 at 13:17:05 UTC, aliak wrote: > >> Ah. Is there any case where you would not want to do that when you have a T value as parameter? > > Hypothetically, yes, e.g. an object that contains references to itself. However, D operates on the assumption that you don't have such objects. The spec actually forbids you creating self referencing structs. DIP 1014 tackles that. For the spec, see https://dlang.org/spec/garbage.html#pointers_and_gc |
December 16, 2018 Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Q. Schroll | On Sunday, 16 December 2018 at 04:02:57 UTC, Q. Schroll wrote:
> On Thursday, 13 December 2018 at 23:33:39 UTC, Stanislav Blinov wrote:
>> On Thursday, 13 December 2018 at 13:17:05 UTC, aliak wrote:
>>
>>> Ah. Is there any case where you would not want to do that when you have a T value as parameter?
>>
>> Hypothetically, yes, e.g. an object that contains references to itself. However, D operates on the assumption that you don't have such objects.
>
> The spec actually forbids you creating self referencing structs. DIP 1014 tackles that. For the spec, see https://dlang.org/spec/garbage.html#pointers_and_gc
I know. What I mean is (what you left out) the language can't statically check that, so even if you were to violate the spec in that regard, you won't get any help from the compiler, and only a little from a handful of library functions. At runtime.
|
Copyright © 1999-2021 by the D Language Foundation