Multiple distinct objects: Difference between revisions
(Added Java, changed some code tags to tt tags) |
(Added C++) |
||
Line 10: | Line 10: | ||
=={{header|C}}== |
=={{header|C}}== |
||
⚫ | |||
foo *foos = malloc(n * sizeof(*foos)); |
|||
for (int i = 0; i < n; i++) |
for (int i = 0; i < n; i++) |
||
init_foo(&foos[i]); |
init_foo(&foos[i]); |
||
</code> |
|||
(Or if no particular initialization is needed, skip that part, or use <tt>calloc</tt>.) |
(Or if no particular initialization is needed, skip that part, or use <tt>calloc</tt>.) |
||
=={{header|C++}}== |
|||
Using only language primitives: |
|||
<code cpp> |
|||
// this assumes T is a default-constructible type (all built-in types are) |
|||
T* p = new T[n]; // if T is POD, the objects are uninitialized, otherwise they are default-initialized |
|||
// ... |
|||
// when you don't need the objects any more, get rid of them |
|||
delete[] p; |
|||
</code> |
|||
Using the standard library |
|||
<code cpp> |
|||
#include <vector> |
|||
// this assumes T is default-constructible |
|||
std::vector<T> vec1(n); // all n objects are default-initialized |
|||
// this assumes t is a value of type T (or a type which implicitly converts to T) |
|||
std::vector<T> vec2(n, t); // all n objects are copy-initialized with t |
|||
</code> |
|||
Instead of <tt>vector</tt>, <tt>deque</tt> or <tt>list</tt> can be used. Note that with standard containers, you don't need to explicitly destroy the objects. |
|||
For polymorphic objects: |
|||
<code cpp> |
|||
#include <vector> |
|||
// this assumes Base is a polymorphic type which has a clone method for polymorphic copying, |
|||
// and p is a pointer to Base or to a type derived from Base. |
|||
// the following is NOT correct: |
|||
std::vector<Base*> bvec_WRONG(n, p); // create n copies of p, which all point to the same opject p points to. |
|||
// nor is this: |
|||
std::vector<Base*> bvec_ALSO_WRONG(n, p->clone()); // create n pointers to a single clone of *p |
|||
// the correct solution |
|||
std::vector<Base*> bvec(n); |
|||
for (int i = 0; i < n; ++i) |
|||
bvec[i] = p->clone(); |
|||
// ... |
|||
// because the container contains pointers, the objects have to be explicitly deleted |
|||
// using a smart pointer like boost::shared_ptr instead would make this step unnecessary |
|||
for (int i = 0; i < vec.size(); ++i) |
|||
delete bvec[i]; |
|||
bvec.resize(0); // make sure the dangling pointers are not used any more |
|||
// (not necessary if bvec isn't used afterwards; alternatively, |
|||
// set the pointers to 0 after deleting; again, using a smart pointer |
|||
// would remove this need) |
|||
</code> |
|||
Of course, also in this case one can use the other sequence containers or plain new/delete instead of <tt>vector</tt>. |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
The mistake is often written as one of these: |
The mistake is often written as one of these: |
||
<code lisp> |
|||
⚫ | |||
(make- |
(make-list n :initial-element (make-the-distinct-thing)) |
||
⚫ | |||
</code> |
|||
which are incorrect since <tt>(make-the-distinct-thing)</tt> is only evaluated once. A common correct version is: |
which are incorrect since <tt>(make-the-distinct-thing)</tt> is only evaluated once. A common correct version is: |
||
<code lisp> |
|||
(loop repeat n collect (make-the-distinct-thing)) |
|||
</code> |
|||
which evaluates <tt>(make-the-distinct-thing)</tt> <var>n</var> times and collects each result in a list. |
which evaluates <tt>(make-the-distinct-thing)</tt> <var>n</var> times and collects each result in a list. |
||
Line 27: | Line 86: | ||
If the creator of the distinct thing is in some monad, then one can write |
If the creator of the distinct thing is in some monad, then one can write |
||
<code haskell |
<code haskell> |
||
replicateM n makeTheDistinctThing |
|||
</code> |
|||
in an appropriate do block. If it is distinguished by, say, a numeric label, one could write |
in an appropriate do block. If it is distinguished by, say, a numeric label, one could write |
||
<code haskell |
<code haskell> |
||
map makeTheDistinctThing [1..n] |
|||
</code> |
|||
=={{header|Java}}== |
=={{header|Java}}== |
||
{{works with|Java|1.5+}} |
{{works with|Java|1.5+}} |
||
It's not pretty but it gets the job done. The first method here is the one that does the work. The second method is a convenience method so that you can pass in a <tt>String</tt> of the class name. |
It's not pretty but it gets the job done. The first method here is the one that does the work. The second method is a convenience method so that you can pass in a <tt>String</tt> of the class name. |
||
<code java5> |
|||
public static LinkedList<Object> getNNewObjects(int n, Class c){ |
|||
LinkedList<Object> ans = new LinkedList<Object>(); |
LinkedList<Object> ans = new LinkedList<Object>(); |
||
try { |
try { |
||
Line 49: | Line 113: | ||
throws ClassNotFoundException{ |
throws ClassNotFoundException{ |
||
return getNNewObjects(n, Class.forName(className)); |
return getNNewObjects(n, Class.forName(className)); |
||
} |
|||
⚫ | |||
</code> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
The mistake is often written as: |
The mistake is often written as: |
||
<code python> |
|||
[Foo()] * n # here Foo() can be any expression that returns a new object |
|||
</code> |
|||
which is incorrect since <tt>Foo()</tt> is only evaluated once. A common correct version is: |
which is incorrect since <tt>Foo()</tt> is only evaluated once. A common correct version is: |
||
<code python |
<code python> |
||
[Foo() for i in xrange(n)] |
|||
</code> |
|||
which evaluates <tt>Foo()</tt> <var>n</var> times and collects each result in a list. This last form is also discussed [[Two-dimensional array (runtime)#Python|here]], on the correct construction of a two dimensional array. |
which evaluates <tt>Foo()</tt> <var>n</var> times and collects each result in a list. This last form is also discussed [[Two-dimensional array (runtime)#Python|here]], on the correct construction of a two dimensional array. |
||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
The mistake is often written as one of these: |
The mistake is often written as one of these: |
||
<code ruby> |
|||
[Foo.new] * n # here Foo.new can be any expression that returns a new object |
|||
Array.new(n, Foo.new) |
Array.new(n, Foo.new) |
||
</code> |
|||
which are incorrect since <tt>Foo.new</tt> is only evaluated once. A common correct version is: |
which are incorrect since <tt>Foo.new</tt> is only evaluated once. A common correct version is: |
||
<code ruby |
<code ruby> |
||
Array.new(n) { Foo.new } |
|||
</code> |
|||
which evaluates <tt>Foo.new</tt> <var>n</var> times and collects each result in an Array. This last form is also discussed [[Two-dimensional array (runtime)#Ruby|here]], on the correct construction of a two dimensional array. |
which evaluates <tt>Foo.new</tt> <var>n</var> times and collects each result in an Array. This last form is also discussed [[Two-dimensional array (runtime)#Ruby|here]], on the correct construction of a two dimensional array. |
Revision as of 17:27, 29 January 2009
You are encouraged to solve this task according to the task description, using any language you may know.
Create a sequence (array, list, whatever) consisting of n distinct items of the same type. n should be determined at runtime.
By distinct we mean that if they are mutable, changes to one do not affect all others; if there is an appropriate equality operator they are considered unequal; etc. The code need not specify a particular kind of distinction, but do not use e.g. a numeric-range generator which does not generalize.
This task was inspired by the common error of intending to do this, but instead creating a sequence of nreferences to the same mutable object; it might be informative to show the way to do that as well.
This task mostly makes sense for languages operating in the pass-references-by-value style (most object-oriented or 'dynamic' languages).
C
foo *foos = malloc(n * sizeof(*foos));
for (int i = 0; i < n; i++)
init_foo(&foos[i]);
(Or if no particular initialization is needed, skip that part, or use calloc.)
C++
Using only language primitives:
// this assumes T is a default-constructible type (all built-in types are)
T* p = new T[n]; // if T is POD, the objects are uninitialized, otherwise they are default-initialized
// ...
// when you don't need the objects any more, get rid of them
delete[] p;
Using the standard library
- include <vector>
// this assumes T is default-constructible
std::vector<T> vec1(n); // all n objects are default-initialized
// this assumes t is a value of type T (or a type which implicitly converts to T)
std::vector<T> vec2(n, t); // all n objects are copy-initialized with t
Instead of vector, deque or list can be used. Note that with standard containers, you don't need to explicitly destroy the objects.
For polymorphic objects:
- include <vector>
// this assumes Base is a polymorphic type which has a clone method for polymorphic copying,
// and p is a pointer to Base or to a type derived from Base.
// the following is NOT correct:
std::vector<Base*> bvec_WRONG(n, p); // create n copies of p, which all point to the same opject p points to.
// nor is this:
std::vector<Base*> bvec_ALSO_WRONG(n, p->clone()); // create n pointers to a single clone of *p
// the correct solution
std::vector<Base*> bvec(n);
for (int i = 0; i < n; ++i)
bvec[i] = p->clone();
// ...
// because the container contains pointers, the objects have to be explicitly deleted
// using a smart pointer like boost::shared_ptr instead would make this step unnecessary
for (int i = 0; i < vec.size(); ++i)
delete bvec[i];
bvec.resize(0); // make sure the dangling pointers are not used any more
// (not necessary if bvec isn't used afterwards; alternatively,
// set the pointers to 0 after deleting; again, using a smart pointer
// would remove this need)
Of course, also in this case one can use the other sequence containers or plain new/delete instead of vector.
Common Lisp
The mistake is often written as one of these:
(make-list n :initial-element (make-the-distinct-thing))
(make-array n :initial-element (make-the-distinct-thing))
which are incorrect since (make-the-distinct-thing) is only evaluated once. A common correct version is:
(loop repeat n collect (make-the-distinct-thing))
which evaluates (make-the-distinct-thing) n times and collects each result in a list.
Haskell
If the creator of the distinct thing is in some monad, then one can write
replicateM n makeTheDistinctThing
in an appropriate do block. If it is distinguished by, say, a numeric label, one could write
map makeTheDistinctThing [1..n]
Java
It's not pretty but it gets the job done. The first method here is the one that does the work. The second method is a convenience method so that you can pass in a String of the class name.
public static LinkedList<Object> getNNewObjects(int n, Class c){
LinkedList<Object> ans = new LinkedList<Object>();
try {
for(int i=0;i<n;i++)
ans.add(c.newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return ans;
}
public static LinkedList<Object> getNNewObjects(int n, String className)
throws ClassNotFoundException{
return getNNewObjects(n, Class.forName(className));
}
Python
The mistake is often written as:
[Foo()] * n # here Foo() can be any expression that returns a new object
which is incorrect since Foo() is only evaluated once. A common correct version is:
[Foo() for i in xrange(n)]
which evaluates Foo() n times and collects each result in a list. This last form is also discussed here, on the correct construction of a two dimensional array.
Ruby
The mistake is often written as one of these:
[Foo.new] * n # here Foo.new can be any expression that returns a new object
Array.new(n, Foo.new)
which are incorrect since Foo.new is only evaluated once. A common correct version is:
Array.new(n) { Foo.new }
which evaluates Foo.new n times and collects each result in an Array. This last form is also discussed here, on the correct construction of a two dimensional array.