@@ -1373,6 +1373,268 @@ $(H3 $(LNAME2 implicit-copy-constructors, Implicit Copy Constructors))
1373
1373
1374
1374
$(P If the generated copy constructor fails to type check, it will receive the `@disable` attribute.)
1375
1375
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
+
1376
1638
1377
1639
$(H2 $(LEGACY_LNAME2 StructPostblit, struct-postblit, Struct Postblits))
1378
1640
0 commit comments