Boost logo

Boost :

From: Daryle Walker (darylew_at_[hidden])
Date: 2008-07-17 22:05:41


On Jul 17, 2008, at 3:19 PM, Ronald Garcia wrote:

> On Jul 11, 2008, at 6:17 AM, Dr Johann A. Briffa wrote:
>
>> I realize this topic has been discussed before (I've seen at least
>> a thread in 2006 and another in 2007), but I believe there is more
>> to add. At issue is the decision that multi_array objects cannot
>> be assigned [with the operator=() that is] unless the target is
>> already the same size as the source. Further, there is no
>> documented way to easily resize an existing array to the same size
>> and range as some other array.
>
> Indeed there is no built-in way to easily resize a multi_array to
> be the same size as another multi_array. While there is no resize
> member function that takes a pointer, there is one that takes a
> model of the Collection concept (classes like boost::array and
> std::vector are concepts). Based on this interface, here is a stop-
> gap non-invasive solution that can resize a multi_array based on
> another model of MultiArray (multi_array, multi_array_ref, etc.):
[TRUNCATE]

Let's define some stuff here:
T: some type you created, probably a class type
a: an object of type T; it's valid, i.e. meets its invariants
b: another object of type T, also valid; any similarities or
differences in its state from a's state is unspecified
C: the set of all valid states an object of type T may have

Let function F: x -> Y, map a T object state x to a (sub)set of C
named Y. This function returns the subset of source states that a
given state can receive during an assignment.

If there exists at least one x in C such that F(x) = Y < C, then type
T is _NOT_ Assignable! In other words, the number of assignment-
compatibility classes in T must be exactly one for T to be
Assignable. Furthermore, an Assignable type requires that the
destination object's observable state post-assignment matches the
observable state of the source object. The destination's new state
can't be the old state quasi-merged with the source's state. (The
destination object's old state must appear to be splattered, but
remnants could be cached to the new state.)

Fortunately, most types are Assignable. What happens if your type
isn't?

1. Users can't use objects of that type in standard containers,
which assume to be able to freely copy objects as much as they want.

2. Such objects are a pain to work with. Any containing class must
write custom assignment operators to add calls to your custom copying
routine. Of course, they have to first check if the source and
destination objects are in the same assignment-compatibility class,
and reconfigure at least one of those two objects if they're not in
the same class. The exception would be if the wrapping class always
makes sure that every T object it creates is of the same class. Even
that is a pain because the user has to manually confirm that
invariant every time s/he changes or adds a mutating function.

3. It isn't safe. You are effectively dumping the responsibility of
assignment onto your users, who won't have all the information. The
user generally has to test compatibility, reconfigure at least one
object, then do call the custom copying routine. These steps are
distinct, so if one of the mutating steps throws, the user will
probably lose his/her old state forever and have a default-valued
object. Your assignment routine would have more information
available, so it can structure the assignment with roll-back during
throws. (This could be moderated with a swap routine that doesn't
care about assignment-compatibility classes. You do have a custom
swap, right? And it does work irrespective of class, right?!)

-- 
Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT hotmail DOT com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk