
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. Let me start with the first issue: others have already said before that making multi_array assignable would be a good thing. Ron disagrees on this point, and from what I gather his principal reason is that multi_array should have the same semantics as multi_array_ref etc. [please do correct me if I'm wrong here, I've only had a day to sort this out]. I am unsure why multi_array_ref etc cannot also have such an interface, but then I haven't used that class enough so my knowledge is very limited there. As far as my needs are concerned, a multi_array that cannot be assigned is next to useless. Allow me to elaborate: I am using multi_array as a replacement to my own (old) 2/3D containers, as recently I've had need for higher dimensions. I have classes containing array members, where the size of the arrays is dynamic through the object lifetime. So my class default constructor uses the array default constructor for its member objects, creating empty arrays. Eventually as my classes get used, the array members are updated accordingly, and get to have some non-zero size. Now the problem is that my classes need to be assignable, and the only way that can be achieved is if the array members are assignable; the alternative is to have to write a specific assignment operator for any of my classes that use arrays, resizing each member of the target before copying. Clearly that would involve a lot of extra effort. The second (admittedly minor) problem is that the only way to resize the target is unclean and the semantics are bound to the dimensionality: target.resize(boost::extents[source.shape()[0]][source.shape()[1]]); etc. I would rather have something like: target.resize(source.extents()); Ron had mentioned in 2007 that the lack of such an interface was an oversight, but there is still no solution. I am bringing up these issues again because: 1) I am not convinced there is any valid reason not to have multi_array assignable. I do not buy the performance issue, as this would only kick in if (a) assignment is within a performance-sensitive path and (b) the target is not already of the same size. Further, at the very least there could be a derived class (somewhat like what I document below) that allows such assignment. 2) It would be nice to have the clean resize interface as part of the multi_array class. As an interim solution for myself, I derived a new class from multi_array that allows assignment and does the resize automagically. I am copying the code below for public benefit. Notes: i) anyone is free to (re)use this code under the same license as multi_array; in particular, Ron, please do feel free to adapt and reuse within a future multi_array as you see fit. ii) while the interface provided is sufficient for the way I use the class, it certainly needs to be adapted to be completely generic. Johann #ifndef __multi_array_h #define __multi_array_h #include "config.h" #include <boost/multi_array.hpp> namespace boost { /*! \brief Assignable version of Boost MultiArray. \author Johann Briffa \par Version Control: - $Revision: 1488 $ - $Date: 2008-07-11 10:35:16 +0100 (Fri, 11 Jul 2008) $ - $Author: jabriffa $ */ template<typename T, std::size_t NumDims> class assignable_multi_array : public multi_array<T,NumDims> { public: /*! \name Constructors / Destructors */ explicit assignable_multi_array() : multi_array<T,NumDims>() {}; explicit assignable_multi_array(const detail::multi_array::extent_gen<NumDims>& ranges) : multi_array<T,NumDims>(ranges) {}; explicit assignable_multi_array(const assignable_multi_array& x) : multi_array<T,NumDims>(dynamic_cast< const multi_array<T,NumDims>& >(x)) {}; // @} /*! \name Assignment */ assignable_multi_array& operator=(const assignable_multi_array& x) { if(!std::equal(this->shape(), this->shape()+this->num_dimensions(), x.shape())) { resize(x.extents()); for(std::size_t i=0; i<NumDims; i++) libbase::trace << "Output Extent " << i << " = " << this->shape()[i] << "\n"; } dynamic_cast< multi_array<T,NumDims>& >(*this) = dynamic_cast< const multi_array<T,NumDims>& >(x); return *this; } // @} /*! \name Informative functions */ /*! \brief Get array extents description Returns an object describing the array extents, in a format suitable for use with resize(). */ detail::multi_array::extent_gen<NumDims> extents() const { typedef typename multi_array<T,NumDims>::extent_range extent_range; detail::multi_array::extent_gen<NumDims> extents_list; for(std::size_t i=0; i<NumDims; i++) { extents_list.ranges_[i] = extent_range(this->index_bases()[i], this->index_bases()[i]+this->shape()[i]); libbase::trace << "Input Extent " << i << " = " << this->shape()[i] << "\n"; } return extents_list; } // @} }; }; // end namespace #endif