aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/mozilla/tech/xpcom/guide/arrays/index.html
blob: 53939ba6c0d12b7c41976a2de6412615a689d13a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
---
title: Array
slug: Mozilla/Tech/XPCOM/Guide/Arrays
tags:
  - XPCOM
  - 所有分类
translation_of: Mozilla/Tech/XPCOM/Guide/Arrays
---
<p> </p>
<h2 id="Introduction" name="Introduction">Introduction</h2>
<h4 id="Array_types" name="Array_types">Array types</h4>
<p>Mozilla has many array classes because each array is optimized for a particular usage pattern. This guide describes the available arrays as well as the enumerator classes that can be used to get to them. In this document the term Array refers to a container for multiple objects with a numeric, zero-based index.</p>
<p>The standard array classes are:</p>
<ul>
 <li><code><a href="#nsIArray_.2F_nsIMutableArray">nsIArray</a></code> - a scriptable container for scriptable XPCOM objects. This array is read-only, and the interface does not provide any methods that will allow adding and removing members.</li>
 <li><code>nsIMutableArray</code> - a scriptable container for scriptable XPCOM objects, which allows addition and removal of member objects. This interface actually derives from nsIArray.</li>
 <li><code>nsCOMArray<span class="nowiki">&lt;T&gt;</span></code> - a C++ class which provides a typesafe, reference-counted container for pointers to a single type of COM object. This class is more or less a wrapper around nsVoidArray and thus shares most of its semantics.</li>
 <li><code>nsTArray<span class="nowiki">&lt;T&gt;</span></code> - a C++ class which provides a typesafe container for objects or primitive types (pointers, integers, etc). The objects must define a default constructor and a copy constructor. To use <code>IndexOf</code> without providing a comparator, they must also define an <code>operator==</code>. For sorting without providing a comparator they must define an <code><span class="nowiki">operator&lt;</span></code>. Note that this class differs from the other array types by using unsigned indices.</li>
 <li><code>nsVoidArray</code> - a C++ class which provides a generic container for any objects using the generic void * type.</li>
 <li><code>nsStringArray</code> / <code>nsCStringArray</code> - a set of C++ classes for holding lists of string objects. Derived from nsVoidArray</li>
 <li><code>nsAutoVoidArray</code> - a version of nsVoidArray which includes 8 entries of internal storage for the array data.</li>
 <li><code>nsSmallVoidArray</code> - a replacement for nsVoidArray which is optimized to hold zero or one element.</li>
</ul>
<p>This handy chart may make it easier to understand the different arrays:</p>
<table class="fullwidth-table">
 <tbody>
  <tr>
   <th>Class</th>
   <th>Data Type</th>
   <th>Scriptable?</th>
   <th>Typesafe?</th>
   <th>Can be modified?</th>
   <th>Built in buffer?</th>
   <th>Ownership</th>
  </tr>
  <tr class="even">
   <td><code><a href="#nsIArray_.2F_nsIMutableArray">nsIArray</a></code></td>
   <td>XPCOM object</td>
   <td>Yes</td>
   <td>No</td>
   <td>No</td>
   <td>No</td>
   <td>Reference Counted, Weak/Strong</td>
  </tr>
  <tr class="odd">
   <td><code>nsIMutableArray</code></td>
   <td>XPCOM object</td>
   <td>Yes</td>
   <td>No</td>
   <td>Yes</td>
   <td>No</td>
   <td>Reference Counted, Weak/Strong</td>
  </tr>
  <tr class="even">
   <td><code>nsCOMArray&lt;T&gt;</code></td>
   <td>XPCOM object</td>
   <td>No</td>
   <td>Yes</td>
   <td>Yes*</td>
   <td>No</td>
   <td>Reference Counted, Strong</td>
  </tr>
  <tr class="odd">
   <td><code>nsTArray&lt;T&gt;</code></td>
   <td>Any that has a default constructor and copy constructor</td>
   <td>No</td>
   <td>Yes</td>
   <td>Yes*</td>
   <td>No</td>
   <td>Can hold objects directly, in which case it owns them. When holding pointers, doesn't own the pointer.</td>
  </tr>
  <tr class="even">
   <td><code>nsVoidArray</code></td>
   <td>Any</td>
   <td>No</td>
   <td>No</td>
   <td>Yes*</td>
   <td>No</td>
   <td>Weak / None</td>
  </tr>
  <tr class="odd">
   <td><code>nsStringArray</code><br>
    <code>nsCStringArray</code></td>
   <td><code>nsString</code><br>
    <code>nsCString</code></td>
   <td>No</td>
   <td>Yes</td>
   <td>Yes*</td>
   <td>No</td>
   <td>Private (copies strings)</td>
  </tr>
  <tr class="even">
   <td><code>nsAutoVoidArray</code></td>
   <td>Any</td>
   <td>No</td>
   <td>No</td>
   <td>Yes*</td>
   <td>Yes</td>
   <td>Weak / None</td>
  </tr>
  <tr class="odd">
   <td><code>nsSmallVoidArray</code></td>
   <td>Any</td>
   <td>No</td>
   <td>No</td>
   <td>Yes*</td>
   <td>No</td>
   <td>Weak / None</td>
  </tr>
  <tr class="even">
   <td><code>nsISupportsArray</code></td>
   <td>XPCOM Object</td>
   <td>Yes</td>
   <td>No</td>
   <td>Yes*</td>
   <td>No</td>
   <td>Reference Counted, Strong</td>
  </tr>
 </tbody>
</table>
<p>(*) Note: Concrete C++ arrays can be made read-only by declaring them const. For example:</p>
<pre class="eval">// HandleList cannot modify the array because of const
void HandleList(const nsVoidArray&amp;);
</pre>
<h4 id="In-place_enumeration" name="In-place_enumeration">In-place enumeration</h4>
<p>Most of the arrays presented here provide callback-style means to enumerate members of an array. Instead of incrementally accessing each element of the array by its index, the arrays provide a way to pass in a callback function that will be called for each element in the array.</p>
<p>For most concrete C++ classes like <code>nsVoidArray</code> and <code>nsCOMArray&lt;T&gt;</code>, indexing should be faster than the callback-style enumeration, because accessing an indexed member of such an array is usually very fast, while enumeration has slight function call overhead. In the case of scriptable arrays like nsIArray however, the enumeration mechanism is often preferred because it avoids the AddRef / Release overhead that comes from accessing each object.</p>
<p>The only functional drawback to in-place enumeration is that you cannot manipulate the array itself during the enumeration. For example, you should not delete elements of an array during the enumeration as this will often confuse the loop which is enumerating the array.</p>
<h4 id="Enumerators" name="Enumerators">Enumerators</h4>
<p>Most arrays provide access to an object which is used to enumerate members of the array. These Enumerators maintain state about the current position in the array. Enumerators are used to access the elements in an ordered way, without relying on the underlying array type. These enumerators include:</p>
<ul>
 <li><code>nsISimpleEnumerator</code> - an enumerator for COM objects.</li>
 <li><code>nsIStringEnumerator</code> / <code>nsIUTF8StringEnumerator</code> - enumerators for strings</li>
</ul>
<h4 id="Obsolete_arrays_.2F_enumerators" name="Obsolete_arrays_.2F_enumerators">Obsolete arrays / enumerators</h4>
<p>There are some deprecated classes which <b>should not be used by new code</b>.</p>
<ul>
 <li><code>nsISupportsArray</code> - obsoleted by <code><a href="#nsIArray_.2F_nsIMutableArray">nsIArray</a></code>, use that instead.</li>
 <li><code>nsIEnumerator</code> - obsoleted by <code>nsISimpleEnumerator</code>, use that instead.</li>
 <li><code>nsIBidirectionalEnumerator</code> - obsoleted by <code>nsISimpleEnumerator</code>, use that instead.</li>
 <li><code>nsVoidArray</code> - <code>nsTArray<span class="nowiki">&lt;T&gt;</span></code> is preferred. Using <code>nsAutoVoidArray</code> is still ok, since that saves an allocation over using <code>nsTArray<span class="nowiki">&lt;T&gt;</span>(8)</code>.</li>
</ul>
<h2 id="Which_Array_should_I_use.3F" name="Which_Array_should_I_use.3F">Which Array should I use?</h2>
<p>Do not use <code>nsISupportsArray</code>; it is deprecated.</p>
<p>Does your array need to be scriptable? If so, use <code>nsIArray</code>.</p>
<p>Example: an array attribute in an IDL file would be <code>nsIArray</code>.</p>
<p>Will your array store non-refcounted objects and need automatic resizing? If so, use <code>nsTArray<span class="nowiki">&lt;T&gt;</span></code>.</p>
<p>Example: an array of integers or an array of strings.</p>
<p>Will your array store non-refcounted objects and be a fixed size? If so, just use a native C++ array unless you need the enumeration options on <code>nsTArray<span class="nowiki">&lt;T&gt;</span></code>.</p>
<p>Example: an array of error message static const char* pointers.</p>
<p>Are all the things you are storing interface pointers to instances of the same interface? If so, use <code>nsCOMArray</code>.</p>
<p>Example: a content node's list of <code>nsIContent</code> children.</p>
<p>Otherwise use <code>nsIArray</code> and make liberal use of <code>QueryElementAt()</code>.</p>
<p>The point of <code>nsCOMArray</code> is that it's a template, and all the pointers in it must be pointers to the same type; it's nice to be able to use it because you get type-safety and don't have to spend time and code QIing (like you have to with <code>nsIArray</code>).</p>
<h2 id="Array_Guidelines" name="Array_Guidelines">Array Guidelines</h2>
<p>Here are a few simple rules which will keep your code clean and your developers happy:</p>
<ul>
 <li>Use typesafe arrays like <code>nsCOMArray<span class="nowiki">&lt;T&gt;</span></code> <code>nsTArray<span class="nowiki">&lt;T&gt;</span></code> wherever possible.</li>
 <li>Avoid all obsolete arrays and enumerators.</li>
 <li>Avoid creating temporary arrays.</li>
</ul>
<h2 id="Scriptable_Arrays" name="Scriptable_Arrays">Scriptable Arrays</h2>
<h3 id="nsIArray_.2F_nsIMutableArray" name="nsIArray_.2F_nsIMutableArray">nsIArray / nsIMutableArray</h3>
<h4 id="Usage" name="Usage">Usage</h4>
<p><code>nsIArray</code> is useful if you need to pass arrays of COM objects through interfaces or require a scriptable array. It can hold strong or weak references to its container objects. This basic interface only allows querying of existing elements in the array. The methods that modify the array have been broken out into <code>nsIMutableArray</code>.</p>
<p>An <code>nsIArray</code> implementation can be created from C++ with the function <code>NS_NewArray(nsIMutableArray**);</code>. The created array implements <code>nsIMutableArray</code> and <code>nsIArray</code>. Since <code>nsIArray</code> derives from <code>nsIMutableArray</code>, the resulting array can be cast to a read-only array.</p>
<pre class="eval">void GetList(nsIArray** aResult) {
  nsCOMPtr&lt;nsIMutableArray&gt; array;
  NS_NewArray(getter_AddRefs(array));

  // append some elements
  ...

  // return it to the caller
  *aResult = array;
  NS_ADDREF(*aResult);
}
</pre>
<h4 id="Access_to_elements" name="Access_to_elements">Access to elements</h4>
<p>Since <code>nsIArray</code> is a regular XPCOM object, its interfaces follows the standard conventions of ownership. Access to specific elements is through <code>QueryElementAt</code>, which is similar to <code>QueryInterface</code>, but it takes a specific index.</p>
<pre class="eval">void NotifyObservers(nsIArray* aArray) {
  PRUint32 length;
  aArray-&gt;GetLength(&amp;length);
  for (PRUint32 i=0; i&lt;length; ++i) {
    nsCOMPtr&lt;nsIMyObserver&gt; element;
    aArray-&gt;QueryElementAt(i, NS_GET_IID(nsIElement),
                                getter_AddRefs(element));
    element-&gt;Observe();
  }
}
</pre>
<p>A simpler option is to use the helper <code>do_QueryElementAt</code> which is typesafe.</p>
<pre class="eval">void NotifyObservers(nsIArray* aArray) {
  PRUint32 length;
  aArray-&gt;GetLength(&amp;length);
  for (PRUint32 i=0; i&lt;length; ++i) {
    nsCOMPtr&lt;nsIMyObserver&gt; element =
    do_QueryElementAt(aArray, i);
     element-&gt;Observe();
  }
}
</pre>
<h4 id="Passing_as_a_parameter" name="Passing_as_a_parameter">Passing as a parameter</h4>
<p>Since <code>nsIArray</code> is an XPCOM object, it should be passed as a pointer. To distinguish between read-only arrays and writable arrays, you should make sure to pass a nsIArray or <code>nsIMutableArray</code> as appropriate.</p>
<p>When the array can or should be modified, then use nsIMutableArray:</p>
<pre class="eval">// array is read-only because it uses nsIArray
void PrintSize(nsIArray* elements) {
  PRUint32 count;
  elements-&gt;GetLength(&amp;count);
  printf("There are %d elements.\n", count);
}

// using nsIMutableArray, so callee may modify
void TweakArray(nsIMutableArray* elements) {
  elements-&gt;RemoveElementAt(0);
  elements-&gt;AppendElement(newElement, PR_FALSE);
}
</pre>
<p>While it is usually possible to call <code>QueryInterface</code> on an <code>nsIArray</code> to get access to the <code>nsIMutableArray</code> interface, this is against convention and it should be avoided.</p>
<pre class="eval">// no need for the double-pointer, and this violates XPCOM rules
// which expect acess to a new object
void TweakArray(nsIMutableArray** elements) {
  // ugh, extra indirection!
  *elements-&gt;RemoveElementAt(0);
  *elements-&gt;AppendElement(newElement, PR_FALSE);
}
</pre>
<h4 id="In-place_enumeration_2" name="In-place_enumeration_2">In-place enumeration</h4>
<p>When accessing all members of an <code>nsIArray</code>, in-place enumeration is preferred over indexed access. However, I seem to have forgotten to implement that. Good thing the interface is under review. Sorry!</p>
<h4 id="Enumerators_2" name="Enumerators_2">Enumerators</h4>
<p>Creating an enumerator from an <code>nsIArray</code> is easy. The method <code>Enumerate()</code> returns a <code>nsISimpleEnumerator</code> which accesses all the elements in the array. Often, simply accessing an array by index, using <code>QueryElementAt</code> is faster. See the section on Enumerators to learn when to properly use enumerators.</p>
<p>For example, if you need to iterate an array returned from another object, you might use <code>Enumerate()</code>.</p>
<pre class="eval">...
// get the array
nsCOMPtr&lt;nsIArray&gt; array;
foo-&gt;GetElements(getter_AddRefs(array));

// make an enumerator
nsCOMPtr&lt;nsISimpleEnumerator&gt; enumerator;
array-&gt;Enumerate(getter_AddRefs(enumerator));

// now enumerate the elements
...
</pre>
<h2 id="Typesafe_Arrays" name="Typesafe_Arrays">Typesafe Arrays</h2>
<h3 id="nsCOMArray.3CT.3E" name="nsCOMArray.3CT.3E">nsCOMArray&lt;T&gt;</h3>
<p><code>nsCOMArray&lt;T&gt;</code> is a typesafe wrapper around <code>nsVoidArray</code>, so it has a similar API. It enforces both typesafety and XPCOM reference counting by keeping an owning reference to each element in the array.</p>
<h4 id="Usage_2" name="Usage_2">Usage</h4>
<p>It is most often used as a member of a C++ class to store a list of well-typed XPCOM objects. It is also usually declared as an inline member rather than a pointer. As a class member, <code>nsCOMArray&lt;T&gt;</code> is preferred over <code>nsIArray</code> when access to the array is confined to the class itself.</p>
<p>For example, here is its use in a class:</p>
<pre class="eval">class NodeContainer {
public:
  void AddNode(nsINode* node);

private:
  nsCOMArray&lt;nsINode&gt; mNodes;
};

// typesafety of mNodes ensures that we only append an nsINode*
void NodeContainer::AddNode(nsINode* node) {
  mNodes.AppendObject(node);
}

</pre>
<p><code>nsCOMArray&lt;T&gt;</code> can also be declared on the stack to collect a temporary list of objects and manipulate them. When the object goes out of scope, all its members are released.</p>
<pre class="eval">void ProcessVisibleItems()
{
  // temporary stack-based nsCOMArray
  nsCOMArray&lt;nsIFoo&gt; fooItems;
  GetCompleteList(fooItems);

  // now filter out non visible objects
  // doing this backwards
  PRUint32 i = fooItems.Count();
  while (i &gt; 0) {
    --i;
    PRBool isVisible;
    fooItems[i]-&gt;GetIsVisible(&amp;isVisible);
    if (!isVisible) {
      fooItems.RemoveObjectAt(i);
    }
  }

  // now deal with the processed list
  ProcessList(fooItems);

  // fooItems will release all its members
  // when it goes out of scope
}
</pre>
<h4 id="Access_to_elements_2" name="Access_to_elements_2">Access to elements</h4>
<p><code>nsCOMArray&lt;T&gt;</code> is a concrete C++ class, and so the [] operator is used to access its members. When using the [] operator, the reference count is unchanged. This allows direct processing of array elements without worrying about calling <code>Release()</code>.</p>
<p>For example, this code calls the same method on each member:</p>
<pre class="eval">void NotifyObservers(const nsCOMArray&lt;nsIMyObserver&gt;&amp; observers) {
  // Using [] doesn't leak!
  for (PRInt32 i = observers.Count() - 1; i &gt;= 0 ; i--)
    observers[i]-&gt;Observe();
}
</pre>
<p>Be careful with this though, you could end up with a weak pointer if you're converting from non-nsCOMArray code.</p>
<pre class="eval">// old version, relied on automatic addref
// mElements is an nsISupportsArray*
void GetFirstObject(nsIElement** aResult) {
  // no need to call NS_ADDREF - this does it for you
  mElements-&gt;QueryElementAt(0, NS_GET_IID(nsIElement),
  (void**)aResult);
}

// new version, make sure to call NS_ADDREF()
// mElements is now a nsCOMArray&lt;nsIElement&gt;
void GetFirstObject(nsIElement** aResult) {
  *aResult = mElements[0];
  NS_ADDREF(*aResult);
}
</pre>
<h4 id="Passing_as_a_parameter_2" name="Passing_as_a_parameter_2">Passing as a parameter</h4>
<p>When passing <code>nsCOMArray&lt;T&gt;</code> among functions, the convention is to pass by reference. Also be sure to use const if you want to enforce that the array is read-only.</p>
<p>Here is an example with a read-only and a writable array:</p>
<pre class="eval">// array is read-only because of const
void PrintSize(const nsCOMArray&lt;nsIElements&gt;&amp; elements) {
 printf("There are %d elements.\n", elements.Count());
}

// no const, so we can modify the array
void TweakArray(nsCOMArray&lt;nsIElement&gt;&amp; elements, nsIElement* newElement) {
  elements.RemoveObjectAt(0);
  elements.AppendObject(newElement);
}
</pre>
<h4 id="In-place_enumeration_3" name="In-place_enumeration_3">In-place enumeration</h4>
<p>The callback-based enumeration in <code>nsCOMArray&lt;T&gt;</code> is about as fast as, if not faster than, standard loop-based iteration. The callback mechanism can be useful when integrating with existing callback-style code however.</p>
<p>One particularly nice thing about the callback mechanism is that it is typesafe. For instance:</p>
<pre class="eval">PR_CALLBACK PRBool getFirstVisible(nsIElement* element, void* closure)   {
 PRBool isVisible;
 element-&gt;IsVisible(&amp;isVisible);

 // stop at first object
 if (isVisible) {
  NS_STATIC_CAST(ClosureObject*,closure)-&gt;element = element;
  return PR_FALSE;
 }
 return PR_TRUE;
}

...
// enumerate to find the object
ClosureObject closureObject = { 0 };
if (!mElements.EnumerateForwards(getFirstVisible, closureObject))
             processElement(closureObject-&gt;element);
...
</pre>
<h4 id="Enumerators_3" name="Enumerators_3">Enumerators</h4>
<p>A <code>nsISimpleEnumerator</code> can be created to provide access to a <code>nsCOMArray&lt;T&gt;</code>. When the enumerator is created, it takes a snapshot of the elements in the array, so that the enumerator can outlive the array.</p>
<p>To create the enumerator, use <code>NS_NewArrayEnumerator(nsISimpleEnumerator**, const nsCOMArray&lt;T&gt;&amp;)</code>. For example:</p>
<pre class="eval">// mElements is an nsCOMArray&lt;nsIElement&gt;
nsFoo::GetElements(nsISimpleEnumerator** aResult) {
  return NS_NewArrayEnumerator(aResult, mElements);
}
</pre>
<h3 id="nsTArray.3CT.3E" name="nsTArray.3CT.3E">nsTArray&lt;T&gt;</h3>
<p><code>nsTArray&lt;T&gt;</code> is a typesafe array for holding various objects. It can be used to hold objects directly, not just pointers to objects.</p>
<h4 id="Usage_3" name="Usage_3">Usage</h4>
<p>It is most often used as a member of a C++ class to store a list of well-typed objects. It is also usually declared as an inline member rather than a pointer. As a class member, <code>nsTArray&lt;T&gt;</code> is preferred over <code>nsVoidArray</code>.</p>
<p>For example, here is its use in a class:</p>
<pre class="eval">class MediaList {
public:
  void AddMedium(const nsString&amp; aMedium);

private:
  nsTArray&lt;nsString&gt; mMedia;
};

// typesafety of mMedia ensures that we only append an nsString
void NodeContainer::AddMedium(const nsString&amp; aMedium) {
  mMedia.AppendElement(aMedium);
}

</pre>
<p><code>nsTArray&lt;T&gt;</code> can also be declared on the stack to collect a temporary list of objects and manipulate them. When the object goes out of scope, all its members have their destructors called. Note that if the <code>nsTArray&lt;T&gt;</code> holds pointers to objects, the objects will not be deleted (and hence not have their destructors called).</p>
<pre class="eval">void ProcessVisibleItems()
{
  // temporary stack-based nsTArray
  nsTArray&lt;FooStruct&gt; fooItems;
  GetCompleteList(fooItems);

  // now filter out non visible objects
  // doing this backwards
  PRUint32 i = fooItems.Length();
  while (i &gt; 0) {
    --i;
    PRBool isVisible;
    fooItems[i]-&gt;GetIsVisible(&amp;isVisible);
    if (!isVisible) {
      fooItems.RemoveElementAt(i);
    }
  }

  // now deal with the processed list
  ProcessList(fooItems);

  // fooItems will call the destructors of all the FooStruct objects
  // when it goes out of scope
}
</pre>
<h4 id="Access_to_elements_3" name="Access_to_elements_3">Access to elements</h4>
<p><code>nsTArray&lt;T&gt;</code> is a concrete C++ class, and so the [] operator is used to access its members.</p>
<p>For example, this code calls the same method on each member:</p>
<pre class="eval">void NotifyObservers(const nsTArray&lt;ObserverClass*&gt;&amp; observers) {
  for (PRUint32 i = observers.Length(); i &gt; 0 ; ) {
    --i;
    observers[i]-&gt;Observe();
  }
}
</pre>
<h4 id="Passing_as_a_parameter_3" name="Passing_as_a_parameter_3">Passing as a parameter</h4>
<p>When passing <code>nsTArray&lt;T&gt;</code> among functions, the convention is to pass by reference. Also be sure to use <code>const</code> if you want to enforce that the array is read-only.</p>
<p>Here is an example with a read-only and a writable array:</p>
<pre class="eval">// array is read-only because of const
void PrintSize(const nsTArray&lt;nsElement&gt;&amp; elements) {
 printf("There are %d elements.\n", elements.Length());
}

// no const, so we can modify the array
void TweakArray(nsTArray&lt;nsElement&gt;&amp; elements,
                const nsElement&amp; newElement) {
  elements.RemoveElementAt(0);
  elements.AppendElement(newElement);
}
</pre>
<h4 id="In-place_enumeration_4" name="In-place_enumeration_4">In-place enumeration</h4>
<p>There are no enumerator objects that work on an <code>nsTArray&lt;T&gt;</code>.</p>
<h2 id="C.2B.2B_Arrays" name="C.2B.2B_Arrays">C++ Arrays</h2>
<h3 id="nsVoidArray" name="nsVoidArray">nsVoidArray</h3>
<p><code>nsVoidArray</code> is a concrete C++ class that allows for storage of any arbitrary object. The base type for all objects is void *. When converting to/from a void *, use <code>NS_STATIC_CAST</code> to ensure that no const-ness is lost.</p>
<p>Note that <code>nsVoidArray</code> defines no semantics of ownership of its objects. Depending on its use, the array may either own the objects that it points to, or its member may be pointers to existing objects that are owned by another data structure. Because nsVoidArray itself does not define any ownership rules, it is up to the consumer to know when it is appropriate to free objects out of the array.</p>
<p>This implies that when an <code>nsVoidArray</code> goes out of scope, seperate code must free any memory that is semantically owned by the array. This should always be documented in the declaration of the array instance.</p>
<p><code>nsCOMArray&lt;T&gt;</code> was designed to eliminate some of the overhead of using nsVoidArray when using COM objects. If your code is using <code>nsVoidArray</code> to keep references to COM objects, consider converting it to <code>nsCOMArray&lt;T&gt;</code>.</p>
<h4 id="Usage_4" name="Usage_4">Usage</h4>
<p><code>nsVoidArray</code> is often used as a member variable in a class. Remember to document ownership!</p>
<pre class="eval">struct FooElement {
 ...
};

class nsFoo : nsIFoo {
 ...
 virtual ~nsFoo();
 ...

 private:
 // mElements owns a list of FooElement structs,
 // which must be deleted when this object goes away
 nsVoidArray mElements;

 // mVisibleElements contains weak (non-owning) references
 // to elements in mElements, and does not need to be cleaned up
 nsVoidArray mVisibleElements;
};

nsFoo::~nsFoo() {
 // mVisibleElements is fine, but
 // don't forget to clean up mElements!
 PRUint32 i, count = mElements.Count();
 for (i=0; i&lt;count; ++i)
  delete NS_STATIC_CAST(FooElement*, mElements[i]);
 }

</pre>
<p>As you can see, <code>nsVoidArray</code> has some context-specific overhead to make sure memory is cleaned up appropriately.</p>
<h4 id="Access_to_elements_4" name="Access_to_elements_4">Access to elements</h4>
<p>The [] operator is used to access member variables. Don't forget to use <code>NS_STATIC_CAST()</code>.</p>
<pre class="eval">for (i=0; i&lt;count; ++i) {
 FooElement* element = NS_STATIC_CAST(FooElement*,mElements[i]);
 // now manipulate element
}

</pre>
<h4 id="Passing_as_a_parameter_4" name="Passing_as_a_parameter_4">Passing as a parameter</h4>
<p>Like other concrete C++ classes, passing by reference using the &amp; syntax is preferred.</p>
<h4 id="In-place_enumeration_5" name="In-place_enumeration_5">In-place enumeration</h4>
<h4 id="Enumerators_4" name="Enumerators_4">Enumerators</h4>
<h3 id="nsStringArray_.2F_nsCStringArray" name="nsStringArray_.2F_nsCStringArray">nsStringArray / nsCStringArray</h3>
<h4 id="Usage_5" name="Usage_5">Usage</h4>
<h4 id="Access_to_elements_5" name="Access_to_elements_5">Access to elements</h4>
<h4 id="Passing_as_a_parameter_5" name="Passing_as_a_parameter_5">Passing as a parameter</h4>
<h4 id="In-place_enumeration_6" name="In-place_enumeration_6">In-place enumeration</h4>
<h4 id="Enumerators_5" name="Enumerators_5">Enumerators</h4>
<h3 id="nsAutoVoidArray" name="nsAutoVoidArray">nsAutoVoidArray</h3>
<h4 id="Usage_6" name="Usage_6">Usage</h4>
<h4 id="Access_to_elements_6" name="Access_to_elements_6">Access to elements</h4>
<h4 id="Passing_as_a_parameter_6" name="Passing_as_a_parameter_6">Passing as a parameter</h4>
<h4 id="In-place_enumeration_7" name="In-place_enumeration_7">In-place enumeration</h4>
<h4 id="Enumerators_6" name="Enumerators_6">Enumerators</h4>
<h3 id="nsSmallVoidArray" name="nsSmallVoidArray">nsSmallVoidArray</h3>
<h4 id="Usage_7" name="Usage_7">Usage</h4>
<h4 id="Access_to_elements_7" name="Access_to_elements_7">Access to elements</h4>
<h4 id="Passing_as_a_parameter_7" name="Passing_as_a_parameter_7">Passing as a parameter</h4>
<h4 id="In-place_enumeration_8" name="In-place_enumeration_8">In-place enumeration</h4>
<h4 id="Enumerators_7" name="Enumerators_7">Enumerators</h4>
<h2 id="Enumerators_8" name="Enumerators_8">Enumerators</h2>
<p>Enumerators are very simple, structure-free objects for visiting each member of a set of objects. The enumerators are used as a generic interface for arrays, hashtables, and other constructs which contain one or more objects. When designing public interfaces, enumerators are the preferred mechanism for accessing these structures because they hide the details of the implementation behind the interface.</p>
<h3 id="nsISimpleEnumerator" name="nsISimpleEnumerator">nsISimpleEnumerator</h3>
<p><code>nsISimpleEnumerator</code> is a generic enumerator for enumerating a list of any XPCOM object. There are many implementations of <code>nsISimpleEnumerator</code>, including one that enumerates <code>nsIArray</code> objects, and another one for <code>nsCOMArray</code>. It is very common for other interfaces which support <code>nsISimpleEnumerator</code> to make their own implementations.</p>
<h3 id="nsIStringEnumerator" name="nsIStringEnumerator">nsIStringEnumerator</h3>
<p>String enumerators provide an easy way to pass a list of strings around with minimal copying. Both unicode strings and UTF8-encoded strings are supported. For more information about the different types of strings, see the String Guide.</p>
<p>String enumerators can be created from <code>nsStringArray</code> or <code>nsCStringArray</code> objects. The implementation of the string enumerator interfaces for <code>nsStringArray</code> and <code>nsCStringArray</code> supports conversion between UTF8 and Unicode, and can be QueryInterface'd back and forth between <code>nsIStringEnumerator</code> and <code>nsIUTF8StringEnumerator</code>.</p>
<p>To create an nsIStringEnumerator for an <code>nsStringArray</code>, you can use one of the variations of <code>NS_NewStringEnumerator</code>. There are also corresponding enumerators and helpers for UTF8 strings. In the examples below, <code>NS_NewUTF8StringEnumerator</code> can be used along with <code>nsIUTF8StringEnumerator</code> and <code>nsCStringArray</code>.</p>
<p>This first example demonstrates the case where a class which owns an <code>nsStringArray</code>, and are returns an <code>nsIStringEnumerator</code> to a caller. You can use the variation of <code>NS_NewStringEnumerator</code> that ensures the owner of the array outlives the enumerator. This is necessary because nsStringArray is not reference counted. Without holding a reference to the owner, the enumerator could be left with a dangling pointer to a deleted <code>nsStringArray</code>.</p>
<pre class="eval">class nsFoo : nsIFoo {
...
private:
  nsStringArray mElementNames;
};

nsFoo::GetElementNames(nsIStringEnumerator** aResult)
{
  // pass in "this" to make sure the enumerator
  // holds a reference to "this"
  return NS_NewStringEnumerator(aResult, mElementNames, this);
}
</pre>
<p>One variant of <code>NS_NewStringEnumerator</code> does not require an owner, but should only be used when the lifetime of the enumerator is known to be shorter than that of the array. Often this is used when a method must take a <code>nsIStringEnumerator</code> rather than an <code>nsStringArray</code>, due to some sort of interface constraint.</p>
<pre class="eval">class nsFoo : nsIFoo {
 ...
 // when ProcessElements returns, the enumerator is at the
 // end of the list, and can be released.
 NS_IMETHODIMP ProcessNames(nsIStringEnumerator*);
 private:

 nsStringArray mElementNames;
};

...
nsCOMPtr&lt;nsIStringEnumerator&gt; enumerator;
NS_NewStringEnumerator(getter_AddRefs(enumerator), mElementNames);

// now call a method on "this" that has a known behavior
ProcessNames(enumerator);
// now enumerator is used up, and can be released
...
</pre>
<p>The last version of <code>nsIStringEnumerator</code> takes ownership of an <code>nsStringArray</code> and is responsible for freeing the array when the enumerator is used up.</p>
<pre class="eval">void GetNames(nsIStringEnumerator** aResult)
{
 nsStringArray *resultArray = new nsStringArray;
 resultArray-&gt;AppendString(str1);
 resultArray-&gt;AppendString(str2);

 // enumerator will free resultArray
 return NS_NewAdoptingStringEnumerator(aResult, resultArray);
}
</pre>
<p>As noted above, these implementations of <code>nsIStringEnumerator</code> can also be QueryInterface'd between nsIStringEnumerator and <code>nsIUTF8StringEnumerator</code>. The implementations will properly convert back and forth between UTF8 and Unicode. To ensure that you get the right implementation and the conversion is done in the right direction, make sure that you call the version of <code>NS_NewStringEnumerator</code> or <code>NS_NewUTF8StringEnumerator</code> that corresponds to the array type, not the enumerator type.</p>
<p>For example, if a class has an internal <code>nsCStringArray</code> of UTF8 strings, but needs to implement an interface which returns an nsIStringEnumerator, it should use <code>NS_NewStringEnumerator</code>:</p>
<pre class="eval">class nsFoo : nsIFoo {
 ...
 NS_IMETHOD GetStrings(nsIStringEnumerator** aResult);
</pre>
<pre class="eval"> private:
 nsCStringArray mElementNames;
};

NS_IMETHODIMP
nsFoo::GetStrings(nsIStringEnumerator** aResult) {
 nsresult rv;
 nsCOMPtr&lt;nsIUTF8StringEnumerator&gt; enumerator
 rv = NS_NewUTF8StringEnumerator(getter_AddRefs(enumerator),
                                       mElementNames, this);
 return CallQueryInterface(enumerator, aResult);
}
</pre>
<h2 id="Obsolete_Arrays_and_Enumerators" name="Obsolete_Arrays_and_Enumerators">Obsolete Arrays and Enumerators</h2>
<h3 id="nsISupportsArray" name="nsISupportsArray">nsISupportsArray</h3>
<h3 id="nsIEnumerator_.28includes_nsIBidirectionalEnumerator.29" name="nsIEnumerator_.28includes_nsIBidirectionalEnumerator.29">nsIEnumerator (includes nsIBidirectionalEnumerator)</h3>