Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document Placement NewExpression #4161

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion spec/class.dd
Original file line number Diff line number Diff line change
Expand Up @@ -1439,7 +1439,7 @@ $(H3 $(LNAME2 anonymous, Anonymous Nested Classes))

$(GRAMMAR
$(GNAME NewAnonClassExpression):
$(D new) $(D class) $(GLINK ConstructorArgs)$(OPT) $(GLINK AnonBaseClassList)$(OPT) $(GLINK2 struct, AggregateBody)
$(D new) $(GLINK2 expression, PlacementExpression)$(OPT) $(D class) $(GLINK ConstructorArgs)$(OPT) $(GLINK AnonBaseClassList)$(OPT) $(GLINK2 struct, AggregateBody)

$(GNAME ConstructorArgs):
$(D $(LPAREN)) $(GLINK2 expression, NamedArgumentList)$(OPT) $(D $(RPAREN))
Expand Down
101 changes: 97 additions & 4 deletions spec/expression.dd
Original file line number Diff line number Diff line change
Expand Up @@ -2920,15 +2920,18 @@ $(H3 $(LNAME2 new_expressions, New Expressions))

$(GRAMMAR
$(GNAME NewExpression):
$(D new) $(GLINK2 type, Type)
$(D new) $(GLINK2 type, Type) $(D [) $(GLINK AssignExpression) $(D ])
$(D new) $(GLINK2 type, Type) $(D $(LPAREN)) $(GLINK NamedArgumentList)$(OPT) $(D $(RPAREN))
$(D new) $(GLINK PlacementExpression)$(OPT) $(GLINK2 type, Type)
$(D new) $(GLINK PlacementExpression)$(OPT) $(GLINK2 type, Type) $(D [) $(GLINK AssignExpression) $(D ])
$(D new) $(GLINK PlacementExpression)$(OPT) $(GLINK2 type, Type) $(D $(LPAREN)) $(GLINK NamedArgumentList)$(OPT) $(D $(RPAREN))
$(GLINK2 class, NewAnonClassExpression)

$(GNAME PlacementExpression):
$(LPAREN) $(GLINK AssignExpression) $(RPAREN)
)

$(P $(I NewExpression)s allocate memory on the
$(DDLINK spec/garbage, Garbage Collection, garbage
collected) heap by default.
collected) heap unless there is a $(RELATIVE_LINK2 PlacementExpression, PlacementExpression).
)

$(P `new T` constructs an instance of type `T` and default-initializes it.
Expand Down Expand Up @@ -3037,6 +3040,96 @@ $(H4 $(LNAME2 new_multidimensional, Multidimensional Arrays))
}
-----------

$(H4 $(LNAME2 PlacementExpression, Placement Expression))

$(P The $(I PlacementExpression) explicitly provides the storage for $(I NewExpression) to initialize with
the newly created value, rather than using the $(DDLINK spec/garbage, Garbage Collection, garbage
collected) heap.)

$(P If $(I Type) is a basic type or a struct, the $(I PlacementExpression) must produce an lvalue that has a size
larger or equal to $(D sizeof($(I Type))).)

$(P The $(I Type) of the $(I PlacementExpression) need not be the same as the $(I Type) of the object being created.)

$(P Alternatively, the $(I PlacementExpression) can be a dynamic array, which must represent sufficient memory
for the object being created.)

$(BEST_PRACTICE Using a static array of `void` is preferred for the $(I PlacementExpression).)

$(P The lifetime of the object presented as an lvalue ends with the execution of the $(I NewExpression),
and a new lifetime of the placed object starts after the execution.)

$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
struct S
{
float d;
int i;
char c;
}

void main()
{
S s;
S* p = new (s) S(); // lifetime of s ends, lifetime of *p begins
assert(p.i == 0 && p.c == 0xFF);
}
---
)

(If Type is a class, the $(I PlacementExpression) must produce an lvalue of type that is of a
sufficient size to hold the class object such as `void[__traits(classInstanceSize, Type)]`
or a dynamic array representing sufficient memory for the class object.)

$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
class C
{
int i, j = 4;
}

void main()
{
void[__traits(classInstanceSize, C)] k;
C c = new(k) C;
assert(c.j == 4);
assert(cast(void*)c == cast(void*)k.ptr);
}
---
)

$(P $(I PlacementExpression) cannot be used for associative arrays, as associative arrays
are designed to be on the GC heap. The size of the associative array allocated is determined
by the runtime library, and cannot be set by the user.)

$(P The use of $(PlacementExpression) is not allowed in `@safe` code.)

$(P To allocate storage with an allocator function such as `malloc()`, a simple template can be used:)

$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
import core.stdc.stdlib;

struct S { int i = 1, j = 4, k = 9; }

ref void[T.sizeof] mallocate(T)()
{
return malloc(T.sizeof)[0 .. T.sizeof];
}

void main()
{
S* ps = new(mallocate!S()) S;
assert(ps.i == 1);
assert(ps.j == 4);
assert(ps.k == 9);
}
---
)




$(H3 $(LNAME2 typeid_expressions, Typeid Expressions))

$(GRAMMAR
Expand Down