scoped

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.

template scoped(T)
@system
scoped
(
Args...
)
(
auto ref Args args
)
if (
is(T == class)
)

Members

Functions

scoped
auto scoped(Args args)

Returns the scoped object.

Examples

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

Meta

Suggestion Box / Bug Report