6

I'm starting to learn c++ but I'm stuck in the destructor. We need to implement a vector and this is what I have so far.

#include<string.h>
#include<cassert>
#include<iostream>

using namespace std;
template<class T>
class Vector {
    template<class U> friend ostream& operator<<(ostream&, const Vector<U>&);
private:
    T* data;
    unsigned len;
    unsigned capacity;
public:
    Vector(unsigned = 10);
    Vector(const Vector<T>&);
    virtual ~Vector(void);
    Vector<T>& operator =(const Vector<T>&);
    bool operator==(const Vector<T>&);
    T& operator[](unsigned);
};

//PROBLEM! 
template <class T>
~ Vector() {
    delete data;

}

template<class T>
Vector<T>::Vector(unsigned int _capacity)
{
    capacity = _capacity;
    len = _capacity;
    data = new T[_capacity];
}

template<class T>
Vector<T>::Vector(const Vector<T> & v)
{
    len = v.len;
    capacity = v.capacity;
    data = new T[len];
    for (unsigned int i = 0; i < len; i++)
        data[i] = v.data[i];
}



template<class T>
Vector<T> & Vector<T>::operator = (const Vector<T> & v)
{
    delete[ ] data;
    len = v.len;
    capacity = v.capacity;
    data = new T [len];
    for (unsigned int i = 0; i < len; i++)
        data[i] = v.data[i];
    return *this;
}

template<class T>
bool Vector<T>::operator == (const Vector<T> & v)
{
    bool check = true;
    check &= (len == v.len);
    if (!check) return false;
    check &= (capacity == v.capacity);
    if (!check) return false;
    for (unsigned int i = 0; i < len; i++) {
        check &= (data[i] == v.data[i]);
        if (!check) return false;

    }
    return true;
}

template<class T>
T& Vector<T>::operator[](unsigned int index)
{
    return data[index];
}

The interface is given and I need to implement it. But this is so different from C and Java, that I'm a bit lost.


In the second exercise we need to implement something like this using a) the previous Vector implementation as derived class and b) the Vector as composition class, so maybe we will use the virtual destructor in one of the approaches?

void testAssociativeArray() { 
AssociativeArray<String, int> table;
 table["abc"] = 15;
 table["jkl"] = 12;
 table["xyz"] = 85;
 assert(table["jkl"], 12);
 }

template<class P, class Q>
class Pair {
P p;
Q q; public:
      Pair(const P& _p = P(), const Q& _q = Q()): p(_p), q(_q) {}
      P& objectP() {return p;}
      Q& objectQ() {return q;}
};
j0k
  • 21,914
  • 28
  • 75
  • 84
Daniel
  • 83
  • 1
  • 5
  • Just a note: you can improve your `operator=` by getting the argument passed in by value and using the "copy-and-swap" idiom (http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom) – Felix Dombek Oct 26 '12 at 13:34

3 Answers3

10

First off, why do you think that the destructor should be virtual? Are you using polymorphism?

Second, you are using delete incorrectly for your array.

Since you used:

data = new T[length];

You must use the array syntax:

delete [] data;

Third, you need to put the namespace in front of all of your class function definitions:

template <class T>
Vector<T>::~Vector()
{
    delete [] data;
}

And just for your information, you declare the destructor like so...

virtual ~Vector(void);

As I mentioned, virtual is unnecessary unless you are using this class as a base or derived class in a polymorphic manner. For more information on when you need to use virtual destructors, look at the answer to this question.

In addition, the void in the parameters is also unnecessary. This used to be required in old C standard, but it is not in C++.

You should be able to declare it like so:

~Vector();

If you define AssociativeArray<P,Q> with a has-a relationship to Vector<T>, then you can simply make the class contain a Vector<Pair<P,Q> >. Declaring virtual methods in this case, are not needed, but can still be used--with some extra overhead.

If you define AssociativeArray<P,Q> with a is-a relationship to Vector<Pair<P,Q> >, then you should define some virtual methods in Vector<T>, including a virtual destructor.

The use of virtual methods only matters when using objects polymorphically through pointers and references. See this page.

AssociativeArray<String,Int>* myDerivedMap = new AssociativeArray<String,Int>();
delete myDerivedMap; //NO virtual methods necessary here. using a pointer to derived class

Vector<Pair<String,Int> >* myBaseMap = new AssociativeArray<String,Int>();
delete myBaseMap; //virtual methods ARE necessary here. using a pointer to base class
Community
  • 1
  • 1
Geoff Montee
  • 2,537
  • 11
  • 14
  • Could you please go more in depth with the `virtual`/non-`virtual` part? – Acorbe Oct 26 '12 at 12:11
  • 1
    I linked to another question that explains that in a pretty straight-forward manner. – Geoff Montee Oct 26 '12 at 12:13
  • thank you. Indeed, I was more concerned about design, i.e. why shouldn't he allow one to safely inherit from his `Vector`. Anyway, I found good points here: http://stackoverflow.com/questions/1647298/why-dont-stl-containers-have-virtual-destructors – Acorbe Oct 26 '12 at 12:17
  • 2
    Making the destructor virtual in a derived class does not make the base destructor virtual, so destructing a derived class via a base-class pointer will still not invoke the derived destructor. So, for any class that has the slightest chance to get inherited, it in general makes sense to declare the destructor virtual. – Tilman Vogel Oct 26 '12 at 12:18
  • 2
    Also, if the base class has a virtual destructor, it's unnecessary to declare the destructor in derived classes as virtual. That virtuality is inherited automatically. – Tilman Vogel Oct 26 '12 at 12:19
  • @Daniel Could use more information. You say the `AssociativeArray

    ` class is supposed to *use* the `Vector` class. Do you mean that it is supposed to *derive* from it? Or it is supposed to *contain* A `vector`. It seems like you could implement the class by having `AssociativeArray

    ` contain a `Vector >`.

    – Geoff Montee Oct 26 '12 at 13:10
  • Actually I need to write two versions. An has-it (composition) and a is-it (inherence) and i'm all lost. – Daniel Oct 26 '12 at 13:17
  • 1
    @TilmanVogel - "for any class that has the slightest chance to get inherited": no, for any class that is **designed** to be derived from. Don't add overhead to support possible misuse. – Pete Becker Oct 26 '12 at 14:02
  • @PeteBecker Hm, I would maybe put it like that: Make the destructor virtual unless your class is designed _not_ to be inherited. One reason for that could be performance considerations when you are creating and destructing lots of instances in an inner loop or such. – Tilman Vogel Oct 26 '12 at 20:30
  • @Acorbe Sure, virtuality is inherited not only for the destructor. – Tilman Vogel Oct 26 '12 at 20:31
  • @TilmanVogel - "designed to be derived from" vs. (not) "designed __not__ to be inherited from" -- distinction without a difference. Unless you believe that some classes aren't designed. – Pete Becker Oct 26 '12 at 20:39
3
template<class T> 
Vector<T>::~Vector()
{
    delete [] data;
}

Note that you must use delete [] and not delete

Armen Tsirunyan
  • 120,726
  • 52
  • 304
  • 418
1

Should be

template <class T>
Vector<T>::~Vector() {
    delete[] data;
}
πάντα ῥεῖ
  • 83,259
  • 13
  • 96
  • 175