user2550228
user2550228

Reputation: 175

C++ Custom Vector Class: Pointer Behaviour

I am writing a custom vector class for a course. We are supposed to implement a push_back function that reallocates new memory when the initial array is full. My implementation should work, however when printing the values I always get a "0" as first element, despite pointing to a place in memory where another value is stored. It do not find my mistake, or what is going on here. The other values work.

Here is the code:

#include <initializer_list>
#include <stdexcept>
#include <algorithm>
#include <iostream>

using std::size_t;

class Vector{
  double* data;         //array to store the data
  size_t sz;            //count number of elements in the vector 
  size_t max_sz;        //max elements

public:
  // constructor default max_sz is set to 5
  Vector(size_t n): sz{0}, max_sz{n < 5? 5: n}, data{new double[n]}{}

  double* begin() { return this->data; }  // return a pointer to the first element 

  Vector(std::initializer_list<double> data): Vector(data.size()){
    for(const auto &elem: data){
      this->data[sz++] = elem;
    }
  }
  ~Vector(){ delete[] this->data; }  //destructor

  size_t size() const { return this->sz; }
  size_t capacity() const { return max_sz; };

  double* at(size_t position) { return this->begin() + position; }  //convenience function

  void reset(double* new_data) {this->data = new_data; }    //reset pointer to new array

  void push_back(double value){
     //test if array is "full"
     if (this->size() == this->capacity()) {

    // create a new temp array, copy the values reset the pointer and delete
    Vector temp(this->capacity() * 2);

    //copy elements from this->data to temp
    for (size_t i = 0; i < this->size(); i++) {
      *(temp.at(i)) = *(this->at(i));
    }

    *(temp.at(this->size())) = value;   //"push_back" the value

    //control statements
    std::cout << temp.begin() << " " << *(temp.begin()) << '\n';
    std::cout << "/* message */" << '\n';

    this->reset(temp.begin());   //reset the pointer from this->data to temp

    //more control statements
    std::cout << this->begin() << " " << *(this->begin()) <<'\n';        
    std::cout << "/* message */" << '\n';

    this->sz++;       // increase size

    this->max_sz = temp.capacity();       // update capacity

  } else {
    // stuff to follow
  }
 }
};

Now to main:

#include "vector.h"
int main(int argc, char const *argv[]) {

  Vector a{1,2,3,4,5};   //usie initializer list

  a.push_back(6);        //call push_back 

  //control statements, the same will be call from within push_back
  //this is the core problem, because a.begin() references to the same memory as this->begin()
  //from within a.push_back(), but the values are different. 
  //How can the same memory block save two different values?
  std::cout << a.begin() << " " << *(a.begin()) << '\n';

  //to show that the rest actually works:
  for (size_t i = 0; i < a.size(); i++) {
    std::cout << *(a.begin()+i) << '\n';
  }

  return 0;
}

Output:

0x560db3004ea0 1
/* message */
0x560db3004ea0 1
/* message */
0x560db3004ea0 0
0
2
3
4
5
6

I mean, how is this possible. It's the same place in memory, why is there a 1 when called from inside the push_back function, and a "0" when call from main, despite poiting to the same place in memory?

Upvotes: 0

Views: 257

Answers (1)

drescherjm
drescherjm

Reputation: 10857

Your problem appears that both temp and this own the pointer to the same data after this->reset(temp.begin()); and then temp goes out of scope making access to this->data undefined behavior.

The fix is to call

temp->reset(nullptr);

before temp goes out of scope so that the destructor does not free the data.

Upvotes: 2

Related Questions