Skip to content

Commit a453ed8

Browse files
authored
add move constructor documentation (#4154)
1 parent 0403f92 commit a453ed8

File tree

1 file changed

+262
-0
lines changed

1 file changed

+262
-0
lines changed

spec/struct.dd

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,6 +1373,268 @@ $(H3 $(LNAME2 implicit-copy-constructors, Implicit Copy Constructors))
13731373

13741374
$(P If the generated copy constructor fails to type check, it will receive the `@disable` attribute.)
13751375

1376+
$(H2 $(LEGACY_LNAME2 StructMoveConstructor, struct-move-constructor, Struct Move Constructors))
1377+
1378+
$(P Move constructors are very much like copy constructors. The difference is that copy
1379+
constructors make a copy of the original, while move constructors move the contents of
1380+
the original, and the lifetime of the original ends.)
1381+
1382+
$(NOTE Do not use postblits in the same struct with move constructors.)
1383+
1384+
$(COMMENT $(P A `struct` that defines a move constructor
1385+
is not $(RELATIVE_LINK2 POD, POD).))
1386+
$(P If a move constructor is declared, also declare a copy constructor.)
1387+
1388+
$(P A constructor declaration is a move constructor declaration if it meets
1389+
the following requirements:)
1390+
1391+
$(UL
1392+
$(LI It takes exactly one parameter without a
1393+
$(DDSUBLINK spec/function, function-default-args, default argument),
1394+
followed by any number of parameters with default arguments.)
1395+
1396+
$(LI Its first parameter is not a
1397+
$(DDSUBLINK spec/function, ref-params, `ref` parameter).)
1398+
1399+
$(LI The type of its first parameter is the same type as
1400+
$(DDSUBLINK spec/type, typeof, `typeof(this)`), optionally with one or more
1401+
$(DDLINK spec/const3, Type Qualifiers, type qualifiers) applied to it.)
1402+
1403+
$(LI It is not a
1404+
$(DDSUBLINK spec/template, template_ctors, template constructor declaration).)
1405+
)
1406+
1407+
---
1408+
struct A
1409+
{
1410+
this(ref return scope A rhs) {} // copy constructor
1411+
this(return scope A rhs) {} // move constructor
1412+
this(return scope const A rhs, int b = 7) {} // move constructor with default parameter
1413+
}
1414+
---
1415+
1416+
$(P The move constructor is type checked as a normal constructor.)
1417+
1418+
$(P The move constructor's first parameter only accepts rvalues. An
1419+
lvalue can be coerced into being an rvalue using
1420+
$(DDSUBLINK spec/expression, RvalueExpression, `__rvalue(Expression)`).)
1421+
1422+
$(P If a move constructor is defined, implicit calls to it will be inserted
1423+
in the following situations:)
1424+
1425+
$(OL
1426+
$(LI When a variable is explicitly initialized:)
1427+
1428+
$(SPEC_RUNNABLE_EXAMPLE_RUN
1429+
---
1430+
struct A
1431+
{
1432+
int[] arr;
1433+
this(return scope A rhs) // move constructor
1434+
{
1435+
arr = rhs.arr;
1436+
rhs.arr = null; // do not leave dangling reference to array
1437+
}
1438+
this(ref return scope A rhs) { assert(0); }
1439+
}
1440+
1441+
void main()
1442+
{
1443+
A a;
1444+
a.arr = [1, 2];
1445+
1446+
A b = __rvalue(a); // move constructor gets called
1447+
b.arr[] += 1;
1448+
assert(a.arr is null); // a.arr is gone
1449+
assert(b.arr == [2, 3]);
1450+
}
1451+
---
1452+
)
1453+
1454+
$(LI When a parameter is passed by value to a function:)
1455+
1456+
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
1457+
---
1458+
struct A
1459+
{
1460+
this(return scope A another) {} // move constructor
1461+
this(ref return scope A rhs) { assert(0); }
1462+
}
1463+
1464+
void fun(A a) {}
1465+
1466+
void main()
1467+
{
1468+
A a;
1469+
fun(__rvalue(a)); // move constructor gets called
1470+
// `a` is no longer a valid object
1471+
}
1472+
---
1473+
)
1474+
)
1475+
1476+
$(H3 $(LNAME2 disable-move, Disabled Moving))
1477+
1478+
$(P When a move constructor is defined for a `struct` (or marked `@disable`), the compiler no
1479+
longer $(RELATIVE_LINK2 implicit-move-constructors, implicitly generates) default move constructors for that `struct`:
1480+
)
1481+
1482+
$(SPEC_RUNNABLE_EXAMPLE_FAIL
1483+
---
1484+
struct A
1485+
{
1486+
this(ref A);
1487+
@disable this(A);
1488+
}
1489+
1490+
void main()
1491+
{
1492+
A a;
1493+
A b = __rvalue(a); // error: move constructor is disabled
1494+
}
1495+
---
1496+
)
1497+
1498+
$(P If a `union U` has fields that define a move constructor, whenever an object of type `U`
1499+
is initialized by move, an error will be issued. The same rule applies to overlapped fields
1500+
(anonymous unions).)
1501+
1502+
$(SPEC_RUNNABLE_EXAMPLE_FAIL
1503+
---
1504+
struct S
1505+
{
1506+
this(ref S);
1507+
this(S);
1508+
}
1509+
1510+
union U
1511+
{
1512+
S s;
1513+
}
1514+
1515+
void main()
1516+
{
1517+
U a;
1518+
U b = __rvalue(a); // error, could not generate move constructor for U
1519+
}
1520+
---
1521+
)
1522+
1523+
$(H3 $(LNAME2 move-constructor-attributes, Move Constructor Attributes))
1524+
1525+
$(P The move constructor can be overloaded with different qualifiers applied
1526+
to the parameter (moving from a qualified source) or to the move constructor
1527+
itself (moving to a qualified destination):
1528+
)
1529+
1530+
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
1531+
---
1532+
struct A
1533+
{
1534+
this(ref return scope A another) { assert(0); } // copy constructor
1535+
this(return scope A another) {} // 1 - mutable source, mutable destination
1536+
this(return scope immutable A another) {} // 2 - immutable source, mutable destination
1537+
this(return scope A another) immutable {} // 3 - mutable source, immutable destination
1538+
this(return scope immutable A another) immutable {} // 4 - immutable source, immutable destination
1539+
}
1540+
1541+
void main()
1542+
{
1543+
A a;
1544+
immutable A ia;
1545+
1546+
A a2 = __rvalue(a); // calls 1
1547+
A a3 = __rvalue(ia); // calls 2
1548+
1549+
A b;
1550+
immutable A ib;
1551+
1552+
immutable A b4 = __rvalue(b); // calls 3
1553+
immutable A b5 = __rvalue(ib); // calls 4
1554+
}
1555+
---
1556+
)
1557+
1558+
$(P The `inout` qualifier may be applied to the move constructor parameter in
1559+
order to specify that mutable, `const`, or `immutable` types are treated the same:
1560+
)
1561+
1562+
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
1563+
---
1564+
struct A
1565+
{
1566+
this(ref return scope inout A rhs) immutable { assert(0); }
1567+
this(return scope inout A rhs) immutable {}
1568+
}
1569+
1570+
void main()
1571+
{
1572+
A r1;
1573+
const(A) r2;
1574+
immutable(A) r3;
1575+
1576+
// All call the same move constructor because `inout` acts like a wildcard
1577+
immutable(A) a = __rvalue(r1);
1578+
immutable(A) b = __rvalue(r2);
1579+
immutable(A) c = __rvalue(r3);
1580+
}
1581+
---
1582+
)
1583+
1584+
$(H3 $(LNAME2 implicit-move-constructors, Implicit Move Constructors))
1585+
1586+
$(P A move constructor is generated implicitly by the compiler for a `struct S`
1587+
if all of the following conditions are met:)
1588+
1589+
$(OL
1590+
$(LI `S` does not explicitly declare any move constructors;)
1591+
$(LI `S` defines at least one direct member that has a move constructor, and that
1592+
member is not overlapped (by means of `union`) with any other member.)
1593+
)
1594+
1595+
$(P If the restrictions above are met, the following move constructor is generated:)
1596+
1597+
---
1598+
this(return scope inout(S) src) inout
1599+
{
1600+
foreach (i, ref inout field; src.tupleof)
1601+
this.tupleof[i] = __rvalue(field);
1602+
}
1603+
---
1604+
1605+
$(P If the generated move constructor fails to type check, it will receive the `@disable` attribute.)
1606+
1607+
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
1608+
---
1609+
import core.stdc.stdio;
1610+
1611+
struct T
1612+
{
1613+
int i;
1614+
inout this(ref inout T t) { this.i = t.i - 1; printf("this(ref T)\n"); }
1615+
inout this(inout T t) { this.i = t.i + 1; printf("this(T)\n"); }
1616+
}
1617+
1618+
struct S
1619+
{
1620+
T t;
1621+
}
1622+
1623+
void main()
1624+
{
1625+
S s;
1626+
s.t.i = 3;
1627+
S u = s;
1628+
printf("u.t.i = %d\n", u.t.i);
1629+
assert(u.t.i == 2);
1630+
1631+
S v = __rvalue(u);
1632+
printf("v.t.i = %d\n", v.t.i);
1633+
assert(v.t.i == 3);
1634+
}
1635+
---
1636+
)
1637+
13761638

13771639
$(H2 $(LEGACY_LNAME2 StructPostblit, struct-postblit, Struct Postblits))
13781640

0 commit comments

Comments
 (0)