3

I'm looking for a C++ container that's a cross between boost::array, boost::scoped_array and std::vector.

I want an array that's dynamically allocated via new[] (no custom allocators), contained in a type that has a meaningful copy-constructor.

boost::array is fixed-size, and although I don't need to resize anything, I don't know the size of the array at compile time.

boost::scoped_array doesn't have a copy constructor, and that means that I need to manually add one to each and every class using std::copy (my previous copy-paste intensive solution). This is also error prone, since you better make sure when you add a field that you added the correct initializer to the custom copy constructor; i.e. loads of boilerplate.

std::vector uses some pre-allocation system, and thus does not use operator new[]. This is problematic since it requires custom allocators, and worse, even that's not quite enough since there are some odd corner cases (which I don't fully understand) where return-by-value semantics are concerned that cause problems; I don't want the container to do anything fancy but simply contain a new[]'d array and copy it in it's copy constructor - and preferably overload all the usual suspects to be usable as a collection.

I don't need to resize anything, but the size must be controllable at runtime. Basically, a variant of scoped_array that happens to have a sane copy-constructor (for instance via std::copy) would be fine. Is there a standard collection for something like this?

Basically, I'm looking for a bog-standard dynamically allocated array with value semantics.

Eamon Nerbonne
  • 47,023
  • 20
  • 101
  • 166
  • 1
    The only reason I can think of to force new[] is that you provided your own new[] operator and want the container to use it. There's nothing "problematic" about a vector with the standard allocator -- at all. – sellibitze Nov 05 '09 at 14:58
  • The requirement on 'new[]' is pretty harsh, since the STL was explicitly designed to handle such requests through custom allocators. – Matthieu M. Nov 05 '09 at 15:10
  • std::vector doesn't use the custom allocator for stack-allocated objects (for obvious reasons). This breaks the class I need to use due to memory alignment issues. Not all containers actually do *any* stack-allocation, however - std::vector is just peculiar in this fashion. – Eamon Nerbonne Nov 09 '09 at 08:39
  • Yeah, I suppose a custom allocator would work as long as the container used _only_ that custom allocator, and, for instance, no stack allocation (unlike std::vector). – Eamon Nerbonne Nov 09 '09 at 08:56

2 Answers2

1

Doesn't sound hard to write. Something along the lines of this?

template <typename T> my_array {
    T* m_ptr;
    size_t m_size;
public:
    my_array(size_t sz)
        : m_ptr(new T[sz])
        , m_size(sz)
    {}
    my_array(const my_array &other)
        : m_ptr(new T[other.m_size])
        , m_size(other.m_size)
    {
        std::copy(other.m_ptr, other.m_ptr + other.m_size, m_ptr);
    }
    ~my_array() {
        delete[] m_ptr;
    }

    // ... operator[], etc.
};

Usual disclaimers - this is off the top of my head, has not been compiled or anything.

Neil Gall
  • 579
  • 4
  • 11
  • very nice, some people just dont' realise rolling your own is the best solution sometimes. – Matt Joiner Nov 05 '09 at 14:42
  • 1
    minor thing: add explicit to the first constructor. Otherwise `my_array a; a = 5;` is valid code... – sbk Nov 05 '09 at 15:04
  • 2
    The very problem of this approach of course, is to then write the iterators. By the way, there is a leak in your code and it will crash badly... hint: you did not define the Assignment Operator... and that's why some people just realize that rolling your own is often more complicated than first anticipated... – Matthieu M. Nov 05 '09 at 15:09
  • 1
    A minimal iterator could simpy be `typedef T* iterator; typedef const T* const_iterator` with corresponding begin and end methods. – UncleBens Nov 05 '09 at 15:36
  • 1
    Its also wrong. Please don't make this kind of suggestion unless you know how to do it. Copy Construtor. Assignment operator. Swap method. Copy and swap idium. Iterators. const correct iterators. Access to members etc etc etc. – Martin York Nov 05 '09 at 17:33
  • 1
    Read this for the basics. http://stackoverflow.com/questions/255612/c-dynamically-allocating-an-array-of-objects/255744#255744 – Martin York Nov 05 '09 at 17:35
  • Yeah, and for exactly those reasons, I thought I'd avoid rolling my own - if a standard solution exists ;-). – Eamon Nerbonne Nov 09 '09 at 08:41
1

Inherit privately from std::vector, and then adjust appropriately. For example remove resize(), and perhaps add setsize() and a bool flag to determine if the size has been set.

Your copy constructor can invoke the std::vector copy constructor, and set the flag automatically to prevent further changes.

Matt Joiner
  • 112,946
  • 110
  • 377
  • 526