1

I'm implementing a super simple container for long term memory management, and the container will have inside an array.

I was wondering, what are the actual implications of those two approaches below?

template<class T, size_t C>
class Container
{
public:
   T objects[C];
};

And:

template<class T>
class Container
{
public:
  Container(size_t cap) 
  {
    this->objects = new T[cap];
  }
  ~Container() 
  {
    delete[] this->objects;
  }
  T* objects;
};

Keep in mind that those are minimal examples and I'm not taking into account things like storing the capacity, the virtual size, etc.

Sigma Octantis
  • 903
  • 1
  • 8
  • 25
  • 1
    I would honestly forget about this since you tagged this question with C++. Use std::vector and std::array. – mfnx Dec 19 '19 at 09:40
  • If your container size is known at compile time, go for the first, otherwise, go for the second. In both cases, go for `std::array` and `std::vector`, as proposed by @mfnx. – TonySalimi Dec 19 '19 at 09:44
  • This feels a bit like an *essay* style question. It may be a bit broad. – Galik Dec 19 '19 at 09:45

2 Answers2

2

If the size of the container is known at compile time, like in first example, you should better use std::array. For instance:

template<class T, size_t C>
class Container
{
public:
   std::array<T, C> objects;
};

This has important advantages:

  • You can get access to its element via std::get, which automatically checks that the access is within bounds, at compile time.
  • You have iterators for Container::objects, so you can use all the routines of the algorithm library.

The second example has some important drawbacks:

  • You cannot enforce bounds-check when accessing the elements: this can potentially lead to bugs.
  • What happens if new in the constructor throws? You have to manage this case properly.
  • You need a suitable copy constructor and assignment operators.
  • you need a virtual destructor unless you are sure that nobody derives from the class, see here.

You can avoid all these problems by using a std::vector.

francesco
  • 7,189
  • 7
  • 22
  • 49
  • Nice, didn't know about std::array, which seems to point right in the direction I'm looking for. – Sigma Octantis Dec 19 '19 at 10:08
  • If new in the constructor throws, the array doesn't get created. You could have an allocation error, but you could have a similar error with std::vector. – mfnx Dec 19 '19 at 10:11
1

In addition to @francesco's answer:

First example

In your first example, your Container holds a C-style array. If an instance of the Container is created on the stack, the array will be on the stack as well. You might want to read heap vs stack (or similar). So, allocating on the stack can have advantages, but you have to be careful with the size you give to the array (size_t C) in order to avoid a stack overflow.

You should consider using std::array<T,C>.

Second example

Here you hold a pointer of type T which points to a C-style array which you allocate on the heap (it doesn't matter whether you allocate an instance of Container on the stack or on the heap). In this case, you don't need to know the size at compile time, which has obvious advantages in many situations. Also, you can use much greater values for size_t C.

You should consider using std::vector<T>.

Further research

For further research, read on stack vs heap allocation/performance, std::vector and std::array.

mfnx
  • 2,894
  • 1
  • 12
  • 28
  • That's something to take into account too. std::array avoids the stack problem then? – Sigma Octantis Dec 19 '19 at 10:10
  • 1
    No. The size of the stack is the size of the stack. std::array allocates on the stack, and you can't exceed the stack size. But, if you create Container on the heap, your std::array will be on the heap as well of course (say you have a std::vector of Containers, then the std::array member in Container won't give you a stack overflow). – mfnx Dec 19 '19 at 10:12