Thread overview | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
November 03, 2013 Initialization vs Assignment | ||||
---|---|---|---|---|
| ||||
Hi, Most of the time my D code has been high-level, so I had never considered the following issue. Imagine you have a struct A as a member of a class/struct X (here a struct, to ensure the dtor is called): struct A { int v; this(int v) { this.v = v*2; } ~this() { writefln("~A(%d)", v); } } struct X { A a; this(int v) { a = A(v); writeln("-"); } } void main() { X x = X(42); } Output: ~A(0) - ~A(84) That is, because we don't have C++'s colon initialization syntax, we are paying the cost of initializing (and then destroying) X.a before we assign to it with "a = A(v)" in X's ctor. This seems to be the case even with @disable A.this(), which here does not seem to do anything (does not prevent the default/implicit initialization of X.a, before it is assigned A(v) ). If C++ distinguishes between initialization and assignment to avoid this issue, is there a reason why D can avoid making the distinction? That is a performance issue. How about correctness? For instance: struct A { void* mem; @disable this(); this(int v) { mem = malloc(v); } ~this() { free(mem); } } Now we can't have an A as a member of X? (it would free a null pointer) How have you solved these cases? Do you change it to a PIMPL? What if that's not desirable? What if you don't want to break encapsulation / cleanliness too much? Etc. Is there a good general solution for this issue? |
November 03, 2013 Re: Initialization vs Assignment | ||||
---|---|---|---|---|
| ||||
Posted in reply to Luís Marques | > Now we can't have an A as a member of X? (it would free a null pointer) Actually, there is nothing wrong with calling free on a null pointer. From the C 89 standard: > The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. |
November 03, 2013 Re: Initialization vs Assignment | ||||
---|---|---|---|---|
| ||||
Posted in reply to Luís Marques | It's fixed in 2.064 :-) http://dpaste.dzfl.pl/c292229f Application output: - ~A(84) |
November 03, 2013 Re: Initialization vs Assignment | ||||
---|---|---|---|---|
| ||||
Posted in reply to Luís Marques Attachments:
| 2013/11/4 <luis@luismarques.eu>"@puremagic.com <"\"Luís".Marques"> > Hi, > > Most of the time my D code has been high-level, so I had never considered the following issue. Imagine you have a struct A as a member of a class/struct X (here a struct, to ensure the dtor is called): > > struct A > { > int v; > > this(int v) > { > this.v = v*2; > } > > ~this() > { > writefln("~A(%d)", v); > } > } > > struct X > { > A a; > > this(int v) > { > a = A(v); > writeln("-"); > } > } > > void main() > { > X x = X(42); > } > > Output: > > ~A(0) > - > ~A(84) > > That is, because we don't have C++'s colon initialization syntax, we are > paying the cost of initializing (and then destroying) X.a before we assign > to it with "a = A(v)" in X's ctor. This seems to be the case even with > @disable A.this(), which here does not seem to do anything (does not > prevent the default/implicit initialization of X.a, before it is assigned > A(v) ). > > If C++ distinguishes between initialization and assignment to avoid this issue, is there a reason why D can avoid making the distinction? That is a performance issue. How about correctness? For instance: > > struct A > { > void* mem; > > @disable this(); > > this(int v) > { > mem = malloc(v); > } > > ~this() > { > free(mem); > } > } > > Now we can't have an A as a member of X? (it would free a null pointer) > > How have you solved these cases? Do you change it to a PIMPL? What if that's not desirable? What if you don't want to break encapsulation / cleanliness too much? Etc. Is there a good general solution for this issue? > The issue is timely fixed in 2.064. http://d.puremagic.com/issues/show_bug.cgi?id=9665 https://github.com/D-Programming-Language/dlang.org/pull/404 Therefore with 2.064, the first test case will output following: - ~A(84) Kenji Hara |
November 03, 2013 Re: Initialization vs Assignment | ||||
---|---|---|---|---|
| ||||
Posted in reply to jerro | On Sunday, 3 November 2013 at 16:01:44 UTC, jerro wrote:
>> Now we can't have an A as a member of X? (it would free a null pointer)
>
> Actually, there is nothing wrong with calling free on a null pointer.
> From the C 89 standard:
>
>> The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs.
Oops, right, not the best example. But you get the motivating idea :-)
|
November 03, 2013 Re: Initialization vs Assignment | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kenji Hara | On Sunday, 3 November 2013 at 16:08:26 UTC, Kenji Hara wrote:
> The issue is timely fixed in 2.064.
> http://d.puremagic.com/issues/show_bug.cgi?id=9665
> https://github.com/D-Programming-Language/dlang.org/pull/404
>
> Therefore with 2.064, the first test case will output following:
>
> -
> ~A(84)
>
>
> Kenji Hara
This is really weird. Not the first time that it happens to me. I swear that I'm not reading the pull requests and coming up with made up questions, hah :-) I guess it's a good sign of bug fixing speed!
|
November 03, 2013 Re: Initialization vs Assignment | ||||
---|---|---|---|---|
| ||||
Posted in reply to Luís Marques | On Sunday, 3 November 2013 at 15:38:30 UTC, Luís Marques wrote:
> Hi,
>
> Most of the time my D code has been high-level, so I had never considered the following issue. Imagine you have a struct A as a member of a class/struct X (here a struct, to ensure the dtor is called):
>
> struct A
> {
> int v;
>
> this(int v)
> {
> this.v = v*2;
> }
>
> ~this()
> {
> writefln("~A(%d)", v);
> }
> }
>
> struct X
> {
> A a;
>
> this(int v)
> {
> a = A(v);
> writeln("-");
> }
> }
>
> void main()
> {
> X x = X(42);
> }
>
> Output:
>
> ~A(0)
> -
> ~A(84)
>
> That is, because we don't have C++'s colon initialization syntax, we are paying the cost of initializing (and then destroying) X.a before we assign to it with "a = A(v)" in X's ctor. This seems to be the case even with @disable A.this(), which here does not seem to do anything (does not prevent the default/implicit initialization of X.a, before it is assigned A(v) ).
>
> If C++ distinguishes between initialization and assignment to avoid this issue, is there a reason why D can avoid making the distinction? That is a performance issue. How about correctness? For instance:
>
> struct A
> {
> void* mem;
>
> @disable this();
>
> this(int v)
> {
> mem = malloc(v);
> }
>
> ~this()
> {
> free(mem);
> }
> }
>
> Now we can't have an A as a member of X? (it would free a null pointer)
>
> How have you solved these cases? Do you change it to a PIMPL? What if that's not desirable? What if you don't want to break encapsulation / cleanliness too much? Etc. Is there a good general solution for this issue?
for actual version of dmd, you can use this trick :)
struct A
{
int v;
void opAssign(int v) {
this.v = v;
}
static int opCall(int v) {
return v * 2;
}
~this()
{
writefln("~A(%d)", v);
}
}
|
Copyright © 1999-2021 by the D Language Foundation