Returns the scoped object.
1 class A 2 { 3 int x; 4 this() {x = 0;} 5 this(int i){x = i;} 6 ~this() {} 7 } 8 9 // Standard usage, constructing A on the stack 10 auto a1 = scoped!A(); 11 a1.x = 42; 12 13 // Result of `scoped` call implicitly converts to a class reference 14 A aRef = a1; 15 assert(aRef.x == 42); 16 17 // Scoped destruction 18 { 19 auto a2 = scoped!A(1); 20 assert(a2.x == 1); 21 aRef = a2; 22 // a2 is destroyed here, calling A's destructor 23 } 24 // aRef is now an invalid reference 25 26 // Here the temporary scoped A is immediately destroyed. 27 // This means the reference is then invalid. 28 version (Bug) 29 { 30 // Wrong, should use `auto` 31 A invalid = scoped!A(); 32 } 33 34 // Restrictions 35 version (Bug) 36 { 37 import std.algorithm.mutation : move; 38 auto invalid = a1.move; // illegal, scoped objects can't be moved 39 } 40 static assert(!is(typeof({ 41 auto e1 = a1; // illegal, scoped objects can't be copied 42 assert([a1][0].x == 42); // ditto 43 }))); 44 static assert(!is(typeof({ 45 alias ScopedObject = typeof(a1); 46 auto e2 = ScopedObject(); // illegal, must be built via scoped!A 47 auto e3 = ScopedObject(1); // ditto 48 }))); 49 50 // Use with alias 51 alias makeScopedA = scoped!A; 52 auto a3 = makeScopedA(); 53 auto a4 = makeScopedA(1); 54 55 // Use as member variable 56 struct B 57 { 58 typeof(scoped!A()) a; // note the trailing parentheses 59 60 this(int i) 61 { 62 // construct member 63 a = scoped!A(i); 64 } 65 } 66 67 // Stack-allocate 68 auto b1 = B(5); 69 aRef = b1.a; 70 assert(aRef.x == 5); 71 destroy(b1); // calls A's destructor for b1.a 72 // aRef is now an invalid reference 73 74 // Heap-allocate 75 auto b2 = new B(6); 76 assert(b2.a.x == 6); 77 destroy(*b2); // calls A's destructor for b2.a
Allocates a class object right inside the current scope, therefore avoiding the overhead of new. This facility is unsafe; it is the responsibility of the user to not escape a reference to the object outside the scope.
The class destructor will be called when the result of scoped() is itself destroyed.
Scoped class instances can be embedded in a parent class or struct, just like a child struct instance. Scoped member variables must have type typeof(scoped!Class(args)), and be initialized with a call to scoped. See below for an example.
Note: It's illegal to move a class instance even if you are sure there are no pointers to it. As such, it is illegal to move a scoped object.