Skip to content

Commit 14f3418

Browse files
authored
Document Placement NewExpression (#4161)
1 parent 2b6f270 commit 14f3418

File tree

2 files changed

+98
-5
lines changed

2 files changed

+98
-5
lines changed

spec/class.dd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1520,7 +1520,7 @@ $(H3 $(LNAME2 anonymous, Anonymous Nested Classes))
15201520

15211521
$(GRAMMAR
15221522
$(GNAME NewAnonClassExpression):
1523-
$(D new) $(D class) $(GLINK ConstructorArgs)$(OPT) $(GLINK AnonBaseClassList)$(OPT) $(GLINK2 struct, AggregateBody)
1523+
$(D new) $(GLINK2 expression, PlacementExpression)$(OPT) $(D class) $(GLINK ConstructorArgs)$(OPT) $(GLINK AnonBaseClassList)$(OPT) $(GLINK2 struct, AggregateBody)
15241524

15251525
$(GNAME ConstructorArgs):
15261526
$(D $(LPAREN)) $(GLINK2 expression, NamedArgumentList)$(OPT) $(D $(RPAREN))

spec/expression.dd

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2974,15 +2974,18 @@ $(H3 $(LNAME2 new_expressions, New Expressions))
29742974

29752975
$(GRAMMAR
29762976
$(GNAME NewExpression):
2977-
$(D new) $(GLINK2 type, Type)
2978-
$(D new) $(GLINK2 type, Type) $(D [) $(GLINK AssignExpression) $(D ])
2979-
$(D new) $(GLINK2 type, Type) $(D $(LPAREN)) $(GLINK NamedArgumentList)$(OPT) $(D $(RPAREN))
2977+
$(D new) $(GLINK PlacementExpression)$(OPT) $(GLINK2 type, Type)
2978+
$(D new) $(GLINK PlacementExpression)$(OPT) $(GLINK2 type, Type) $(D [) $(GLINK AssignExpression) $(D ])
2979+
$(D new) $(GLINK PlacementExpression)$(OPT) $(GLINK2 type, Type) $(D $(LPAREN)) $(GLINK NamedArgumentList)$(OPT) $(D $(RPAREN))
29802980
$(GLINK2 class, NewAnonClassExpression)
2981+
2982+
$(GNAME PlacementExpression):
2983+
$(LPAREN) $(GLINK AssignExpression) $(RPAREN)
29812984
)
29822985

29832986
$(P $(I NewExpression)s allocate memory on the
29842987
$(DDLINK spec/garbage, Garbage Collection, garbage
2985-
collected) heap by default.
2988+
collected) heap unless there is a $(RELATIVE_LINK2 placement-expression, *PlacementExpression*).
29862989
)
29872990

29882991
$(P `new T` constructs an instance of type `T` and default-initializes it.
@@ -3091,6 +3094,96 @@ $(H4 $(LNAME2 new_multidimensional, Multidimensional Arrays))
30913094
}
30923095
-----------
30933096

3097+
$(H4 $(LNAME2 placement-expression, Placement Expression))
3098+
3099+
$(P The $(I PlacementExpression) explicitly provides the storage for $(I NewExpression) to initialize with
3100+
the newly created value, rather than using the $(DDLINK spec/garbage, Garbage Collection, garbage
3101+
collected) heap.)
3102+
3103+
$(P If $(I Type) is a basic type or a struct, the $(I PlacementExpression) must produce an lvalue that has a size
3104+
larger or equal to $(D sizeof($(I Type))).)
3105+
3106+
$(P The $(I Type) of the $(I PlacementExpression) need not be the same as the $(I Type) of the object being created.)
3107+
3108+
$(P Alternatively, the $(I PlacementExpression) can be a dynamic array, which must represent sufficient memory
3109+
for the object being created.)
3110+
3111+
$(BEST_PRACTICE Using a static array of `void` is preferred for the $(I PlacementExpression).)
3112+
3113+
$(P The lifetime of the object presented as an lvalue ends with the execution of the $(I NewExpression),
3114+
and a new lifetime of the placed object starts after the execution.)
3115+
3116+
$(SPEC_RUNNABLE_EXAMPLE_RUN
3117+
---
3118+
struct S
3119+
{
3120+
float d;
3121+
int i;
3122+
char c;
3123+
}
3124+
3125+
void main()
3126+
{
3127+
S s;
3128+
S* p = new (s) S(); // lifetime of s ends, lifetime of *p begins
3129+
assert(p.i == 0 && p.c == 0xFF);
3130+
}
3131+
---
3132+
)
3133+
3134+
(If Type is a class, the $(I PlacementExpression) must produce an lvalue of a type that is of a
3135+
sufficient size to hold the class object such as `void[__traits(classInstanceSize, Type)]`
3136+
or a dynamic array representing sufficient memory for the class object.)
3137+
3138+
$(SPEC_RUNNABLE_EXAMPLE_RUN
3139+
---
3140+
class C
3141+
{
3142+
int i, j = 4;
3143+
}
3144+
3145+
void main()
3146+
{
3147+
void[__traits(classInstanceSize, C)] k = void;
3148+
C c = new(k) C;
3149+
assert(c.j == 4);
3150+
assert(cast(void*) c == k.ptr);
3151+
}
3152+
---
3153+
)
3154+
3155+
$(P $(I PlacementExpression) cannot be used for associative arrays, as associative arrays
3156+
are designed to be on the GC heap. The size of the associative array allocated is determined
3157+
by the runtime library, and cannot be set by the user.)
3158+
3159+
$(P The use of $(I PlacementExpression) is not allowed in `@safe` code.)
3160+
3161+
$(P To allocate storage with an allocator function such as `malloc()`, a simple template can be used:)
3162+
3163+
$(SPEC_RUNNABLE_EXAMPLE_RUN
3164+
---
3165+
import core.stdc.stdlib;
3166+
3167+
struct S { int i = 1, j = 4, k = 9; }
3168+
3169+
ref void[T.sizeof] mallocate(T)()
3170+
{
3171+
return malloc(T.sizeof)[0 .. T.sizeof];
3172+
}
3173+
3174+
void main()
3175+
{
3176+
S* ps = new(mallocate!S()) S;
3177+
assert(ps.i == 1);
3178+
assert(ps.j == 4);
3179+
assert(ps.k == 9);
3180+
}
3181+
---
3182+
)
3183+
3184+
3185+
3186+
30943187
$(H3 $(LNAME2 typeid_expressions, Typeid Expressions))
30953188

30963189
$(GRAMMAR

0 commit comments

Comments
 (0)