@@ -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