I’m trying to implement my own version of vector class without using iterators. Here is the parts which may be needed for the question.
template <typename T>
class Vector {
public:
...
~Vector()
{
delete [] m_data;
}
...
void erase(size_t position)
{
if (position >= m_size) {
throw std::out_of_range("erasing an element out of bounds");
}
--m_size;
for (size_t i = position; i < m_size; ++i) {
m_data[i] = m_data[i + 1];
}
m_data[m_size].T::~T();
}
...
private:
T* m_data;
size_t m_size;
...
};
Below is a quote from cplusplus.com for erase function of std::vector:
This effectively reduces the vector size by the number of elements removed, calling each element’s destructor before.
So I tried to implement the same functionality by calling the destructor of the last duplicate element. The destructor of m_data[position] is unnecessary as it will be replaced by the next element.
The problem is that the code in the destructor of vector class delete [] m_data will also call the destructors for each element which will cause double deletion of memory and crash.
Can anyone help to write the correct erase function for my vector class?
What you are trying doesn’t fly that easily! If you want to implement something like
std::vector<T>you need to do the full monty: you need to deal with raw memory and construct/destroy objects explicitly. That is, you need to allocate a sufficient chunk of uninitialized memory, construct/destroy object at their appropriate locations as needed, and eventually release the allocated memory. It is an interesting exercise to do for toy version ofstd::vector<T>and then you’ll gladly use version shipping with your compiler because it somehow managed to be faster, actually implement all of the functionality, and is reasonably bug free. Of course, if you happen to implement a version of the standard C++ library you’ll need to suffer through the entire exercise. The good news is:std::vector<T>is trivial compared tostd::deque<T>which I’d be prepared to bet big bucks you won’t get anywhere nearly as efficient as a standard library version without the use of algorithms (and to get this really efficient you’d need fairly complex version of the algorithms as well; I’m not sure if there are many implementations which actually do specialized versions which are good onstd::deque<T>).Not using iterators for this is, BTW, just not helpful: algorithms like
std::move()(the version taking iterators as arguments) orstd::copy()(if you don’t use C++2011) avoid littering your code with duplicated versions. Having the code in algorithms has the added advantage that they not entirely trivial logic is nicely encapsulated as needed. Putting the repeatedly needed code into algorithms makes the implementation of the containers comparatively simple, giving the implementation a much better chance of being correct. … not to mention that it is actually viable to implement interesting optimizations as well.