0

So I'm trying to write a vector class which can take objects without a default constructor. To do so I'm using an array of raw pointers. Thing is, when I'm instantiating a new vector, let's call it 2, based upon a previous vector, let's call it 1-- it points to the underlying address of said previous object, 1. So when I insert a new value into 1, 2 is updated as well.

#ifndef MYVECTOR_MYVECTOR_H
#define MYVECTOR_MYVECTOR_H

#include <sstream>
#include <stdexcept>
#include <memory>
#include <vector>
#include <ostream>

template<typename T>
class MyVector;

template<typename T>
std::ostream& operator<<(std::ostream& out, const MyVector<T>& myVec){
  out << "{";
  for(int i = 0; i < myVec.numElem; i++){
    out << &myVec.elements[i] << " ";
  }
  out << "}";
  return out;
}


template<typename T>
class MyVector{
  public:
      int numElem;
      int capacity;
      T** elements;

      MyVector(const unsigned int& numElements, const T& value) : numElem(numElements), capacity(numElements * 2){
          elements = new T*[capacity];
          for(int i = 0; i < numElem; i++){
              elements[i] = new T(value);
          }
      }

      template<typename U>
      MyVector(const std::vector<U>& values): numElem(values.size()), capacity(values.size() * 2){
        elements = new T*[capacity];
        for(int i = 0; i < numElem; i++){
            elements[i] = new T(values[i]);
        }
      }

    void insert(const unsigned& pos, const T& value){
        elements[numElem] = new T(*elements[numElem - 1]);
        numElem++;

        for(unsigned int i = numElem - 1; i > pos; i--){
            elements[i] = elements[i - 1];
        }
        elements[pos] = new T(value);
    }
};

#endif

Per comment #1:

class NoDefault {
 public:
  NoDefault(const int& value) : value(value) {}

  int value;
};

std::ostream& operator<<(std::ostream& out, const NoDefault& noDefault) {
  out << noDefault.value;
  return out;
}

int main() {
  MyVector<NoDefault> noDefaultVec(std::vector<NoDefault>{7,8,9,10,11});
  MyVector<MyVector<NoDefault>> vecvec(2, noDefaultVec);

  std::cout << "noDefaultVec = " << noDefaultVec << std::endl;
  std::cout << "vecvec = " << vecvec << std::endl;

  noDefaultVec.insert(3, 99);
  vecvec.insert(1, noDefaultVec);

  std::cout << "noDefaultVec = " << noDefaultVec << std::endl;
  std::cout << "vecvec = " << vecvec << std::endl;

  return 0;
}
  • " when I'm instantiating a new vector, let's call it 2, based upon a previous vector, let's call it 1" - how are you doing this? `MyVector letsCallIt2(letsCallIt1)` ? In that case you need to provide a copy constructor to make a deep copy. (By the way, you will also want to write a destructor to clean up your ` T**` ). – CompuChip Mar 20 '18 at 07:16
  • just in case you do this because `std::vector` cannot hold elements that have no default constructor: `std::vector` can hold elements that have no default constructor, you just cant call any method that would require to default construct an element – 463035818_is_not_an_ai Mar 20 '18 at 07:54
  • "To do so I'm using an array of raw pointers." This would vehave very differently from the standard vector, and thus deserve a completely new name. – n. m. could be an AI Mar 20 '18 at 11:57

1 Answers1

1

You perform a shallow copy instead of a deep copy.

A shallow copy of your vector creates a new collection which shares elements with an old one. What follows, any change made to the original object will cause a change in a new one. What you need in that case is a deep copy, which duplicates every element from the source to the destination. After performing such a copy you are left with two vectors with seperate set of data.

Providing a copy constructor for your class solves the problem, but you should also remember about implementing destructor and assignment operator, basing on The Rule Of Three. You can also consider adding move constructor and move assignment operator (or one assignment operator following copy-and-swap idiom).

Rozek
  • 53
  • 10