Bug 4247 – Cannot create default-constructed struct on heap when constructor is defined
Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2010-05-28T15:55:00Z
Last change time
2014-09-14T14:54:46Z
Keywords
pull, rejects-valid
Assigned to
nobody
Creator
schveiguy
Comments
Comment #0 by schveiguy — 2010-05-28T15:55:49Z
If I want a struct on the heap, I do this:
struct S
{
}
auto s = new S;
But if I give S a constructor:
struct S
{
this(int n) {}
}
auto s = new S;
dmd complains:
Error: constructor S.this (int n) is not callable using argument types ()
So I do this:
struct S
{
this() {}
this(int n) {}
}
but dmd now complains:
Error: constructor S.this default constructor not allowed for structs
So the auto s = new S is no longer usable. However, I can easily declare a struct S on the stack, or create a new array of S. In fact, you can do:
auto s = (new S[1])[0];
and achieve the desired effect, but this is oh so ugly.
Bottom line, if I can construct a struct on the stack, I should be able to identically construct it on the heap.
Comment #1 by andrej.mitrovich — 2010-09-11T06:37:01Z
You can't make your own default constructor for structs, this is explained in TDPL. A constructor with no arguments is created by default, with each field of a struct initialized to it's type's .init property. You cannot override this. See page 244 in TDPL.
Also, since when are structs allowed to be allocated on the heap? TDPL explicitly states that structs have scoped lifetime.
Comment #2 by bearophile_hugs — 2010-09-11T07:00:37Z
(In reply to comment #1)
> Also, since when are structs allowed to be allocated on the heap? TDPL
> explicitly states that structs have scoped lifetime.
I double TDPL says this. And if it says so, then it's wrong. TDPL is not a religious book.
> You cannot override this. See page 244 in TDPL.
The reason given at page 244 is that all type needs a statically defined init.
On the other hand the need to allocate a struct on the heap with no arguments is real, and the current workarounds look bad for a nice language as D2. This small program shows that you can create a S2 on the stack:
struct S1 {}
struct S2 {
this(int) {}
}
void main() {
S1 s1a;
auto s1b = new S1;
S2 s2a; // OK
auto s2b = new S2; // ERR
}
So I think "new S2;" may just create the same struct that "S2 s2a;" creates, but allocate it on the heap instead of the stack. I think this is a solution.
Comment #3 by nfxjfg — 2010-09-11T07:10:59Z
(In reply to comment #1)
> Also, since when are structs allowed to be allocated on the heap? TDPL
> explicitly states that structs have scoped lifetime.
If structs couldn't be allocated on the heap, you'd have to forget about struct arrays. And this is pure bullshit. E.g. this wouldn't be allowed anymore:
S[] array;
array.length = 1;
You couldn't seriously want this to be illegal.
(This code snippet also shows that it's advantageous to force structs having a "simple" default ctor, i.e. one that doesn't require the runtime to run code on each element to construct it.)
Comment #4 by andrej.mitrovich — 2010-09-11T08:00:51Z
(In reply to comment #2)
> (In reply to comment #1)
> > Also, since when are structs allowed to be allocated on the heap? TDPL
> > explicitly states that structs have scoped lifetime.
>
> I double TDPL says this. And if it says so, then it's wrong. TDPL is not a
> religious book.
>
It's not a religious book, but since the D docs aren't kept up to date, who can you trust? And AFAIK Andrei & Walter have both reviewed TDPL and agree with what it states there. As for structs on the heap, I simply didn't know it was possible to do that, so maybe I judged to quickly from what I've read.
Whether it's legal or not is not up to me, so don't take it personal please. :)
Comment #5 by andrei — 2010-09-11T09:57:21Z
(In reply to comment #4)
> (In reply to comment #2)
> > (In reply to comment #1)
> > > Also, since when are structs allowed to be allocated on the heap? TDPL
> > > explicitly states that structs have scoped lifetime.
> >
> > I double TDPL says this. And if it says so, then it's wrong. TDPL is not a
> > religious book.
> >
>
> It's not a religious book, but since the D docs aren't kept up to date, who can
> you trust? And AFAIK Andrei & Walter have both reviewed TDPL and agree with
> what it states there. As for structs on the heap, I simply didn't know it was
> possible to do that, so maybe I judged to quickly from what I've read.
>
> Whether it's legal or not is not up to me, so don't take it personal please. :)
Obviously there are many ways to allocate struct objects on the heap: using new, as members of class objects, or as elements of arrays. All of them are described in TDPL. If some particular sentence of TDPL seems to rule out such possibilities please let me know.
Comment #6 by andrej.mitrovich — 2010-09-11T10:45:49Z
(In reply to comment #5)
> (In reply to comment #4)
> > (In reply to comment #2)
> > > (In reply to comment #1)
> > > > Also, since when are structs allowed to be allocated on the heap? TDPL
> > > > explicitly states that structs have scoped lifetime.
> > >
> > > I double TDPL says this. And if it says so, then it's wrong. TDPL is not a
> > > religious book.
> > >
> >
> > It's not a religious book, but since the D docs aren't kept up to date, who can
> > you trust? And AFAIK Andrei & Walter have both reviewed TDPL and agree with
> > what it states there. As for structs on the heap, I simply didn't know it was
> > possible to do that, so maybe I judged to quickly from what I've read.
> >
> > Whether it's legal or not is not up to me, so don't take it personal please. :)
>
> Obviously there are many ways to allocate struct objects on the heap: using
> new, as members of class objects, or as elements of arrays. All of them are
> described in TDPL. If some particular sentence of TDPL seems to rule out such
> possibilities please let me know.
Described where exactly? I haven't seen any snippet of code using new for struct objects in the structs section from page 240 onwards. There's a mention of using classes inside structs, and dynamic arrays inside structs (where the postblit constructor comes in handy), but no mention on how to use structs on the heap. Maybe it's in a different section..?
Comment #7 by andrej.mitrovich — 2013-02-18T10:05:18Z
(In reply to comment #6)
> Described where exactly?
Please ignore my comments from before as I didn't know at the time 'new'ing was possible for structs.
Comment #8 by maximzms — 2013-04-15T07:09:04Z
(In reply to comment #0)
> So the auto s = new S is no longer usable. However, I can easily declare a
> struct S on the stack, or create a new array of S. In fact, you can do:
>
> auto s = (new S[1])[0];
>
> and achieve the desired effect, but this is oh so ugly.
This code would create structure on the heap and put COPY of it to `s`.
It is not the same as `auto s = new S`.
The workaround should be:
--------------------
auto s = (new S[1]).ptr;
--------------------
Comment #9 by schveiguy — 2013-04-15T10:26:37Z
(In reply to comment #8)
> (In reply to comment #0)
> > So the auto s = new S is no longer usable. However, I can easily declare a
> > struct S on the stack, or create a new array of S. In fact, you can do:
> >
> > auto s = (new S[1])[0];
> >
> > and achieve the desired effect, but this is oh so ugly.
>
> This code would create structure on the heap and put COPY of it to `s`.
> It is not the same as `auto s = new S`.
>
> The workaround should be:
> --------------------
> auto s = (new S[1]).ptr;
> --------------------
Oh yes! I was missing an & :)
Thanks