Constructor for custom vector class assigning extra garbage values to pointers

120 Views Asked by At

Hello its me again with another vector class problem.

Here is my .CPP file

#include "myStringVector.hpp"

  void myStringVector::reserve(int n){
    if(!base){
      base = allocate<myString>(n);
      last = base;
      limit = base+n;
    }
    else{
      myString *p = allocate<myString>(n); //new base
      myString *q = p; //new last
      limit = p + n; //new limit
      myString *i = uninitialized_copy(base, last, q);
      destroy(i);
      deallocate(base);
      base = p; //update base
      last = q; //update last
    }
  }

  myStringVector::myStringVector(){
    this->reserve(0);
  }

  myStringVector::~myStringVector(){
    if(!base){
      deallocate(base);
      deallocate(last);
      deallocate(limit);
    }
    else{
      base = initialized_destroy(base, last);
      deallocate(base);
      deallocate(last);
      deallocate(limit);
    }
  }

  myStringVector::myStringVector(const std::initializer_list<myString>& list){
    std::cout << list.size() << "\n";
    this->reserve(list.size());
    last = uninitialized_copy(list.begin(), list.end(), last);
  }

  int myStringVector::size() const{
    return (last - base);
  }

  bool myStringVector::empty() const{
    return (this->size() == 0);
  }

  myString myStringVector::operator[](int index){
    return *(base+index);
  }

here is my .HPP file

#ifndef MYSTRINGVECTOR_HPP
  #define MYSTRINGVECTOR_HPP

  #include "myString.hpp"

  class myStringVector{
  private:
    myString *base = nullptr;
    myString *last = nullptr;
    myString *limit = nullptr;
  public:
    void reserve(int);
    myStringVector();
    ~myStringVector();
    myStringVector(const std::initializer_list<myString>&);
    int size() const;
    bool empty() const;
    myString operator[](int);

  };

  #endif //MYSTRINGVECTOR_HPP_INCLUDED

also using these functions...

template<typename T>
  inline T* uninitialized_copy(T const* first, T const* last, T* out)
  {
    while (first != last) {
      construct(out, *first);
      ++out;
      ++first;
    }
    return out;
  }

...

template<typename T>
  inline T* initialized_destroy(T* first, T* last)
  {
    while (first != last) {
      destroy(first);
      ++first;
    }
    return first;
  }

...

template<typename T, typename... Args>
  inline T* construct(T* p, Args&&... args)
  {
    return new (p) T(std::forward<Args>(args)...);
  }

...

template<typename T>
  inline T* allocate(int n)
  {
    return reinterpret_cast<T*>(::operator new(n * sizeof(T)));
  }

and...

template<typename T>
  inline void deallocate(T* p)
  {
    ::operator delete(p);
  }

my main does this...

{
myStringVector v;
assert(v.empty());
std::cout << "Passed default ctor" << std::endl;
myStringVector v1 {"a", "b", "c"};
myStringVector v2 {"d", "e", "f"};
std::cout << v1.size() << " " << v2.size() << "\n";
std::cout << v1[0] << v1[1] << v1[2];
}

myString is just a custom string class. It works like a normal string class.

When I run main, I am expecting v1 to hold a, b, and c. And v2 to hold d, e, and f. But this is what I get...

ap÷bp÷cp÷

so it looks like it is initializing each index with extra garbage after each character. I've tried directly initializing without using reserve() and uninitialized_copy and it works fine. However, I am required to use these confusing memory management functions by my professor. I assume I am using the functions incorrectly, but its hard to know what to fix when the compiler doesnt give me any errors.

If anyone could help me see what I am doing wrong and why I am seeing garbage values I'd really appreciate it.

Thanks!

1

There are 1 best solutions below

3
On

You say

myString is just a custom string class

But how did you implement it?

My immediate impression is that your custom string class is copying the characters and failing to put a terminating null at the end of them.

The other key point is that you are using cout so you need to know how your custom string is being written. eg: if you have an operator const char* then that will have been picked up, and the stream output will be expecting a true C String with terminating null.

see the oofString output

ostream& 
operator<<(ostream& os, const oofString& str)
{
    os << str.chars();
    return os;
}

Where chars() is defined as:

inline const char*
oofString::chars() const
{
    if (mBody)
        return mBody;
    else
        return "";
}

Nothing I see in this question points to the myStringVector as being the source of the problem.