I was working with my own "Vector"-like class and thought about something.

If I use the [] operator and return a reference, is there any way to mark that indice when a value is assigned to it?

For example.. if I want to make a trim function that removes the "garbage" information when I allow the user to specify a size for the Array Class and call trim.

Here's the code in case you need to see it.

#pragma once

/*

MyLibrary.h

Meant to be used with stack-objects only. Namely primitive types (hence the name).
*/

template<typename P>
class PrimArray{
      private:
              P *value;
              int currentSize;
              
      public:
             PrimArray(){
                  int temp = 1;           
                  value = (P*)malloc(temp * sizeof(P)); 
                  currentSize = temp;      
             };
             
             P *copyContents(){//returns a deep copy of this array-class
                  P *copy = (P*)malloc(currentSize * sizeof(P));
                  
                  for(int i = 0; i < currentSize; i++)
                          copy[i] = (*this)[i];
                  
                  return copy;            
             }
             
             ~PrimArray(){free((void*)value);};
             
             int length(){return currentSize;};
             
             bool storeValue(P arg, int location){
                 if(location >= 0 && location < currentSize){         
                   (*this)[location] = arg;
                    return true;
                 }
                 else if(location == currentSize){
                     P *temp = (P*)malloc(currentSize * sizeof(P));
                     
                     for(int i = 0; i < currentSize; i++)
                          temp[i] = (*this)[i];
                      
                     currentSize++;
                     free((void*)value);
                     value = (P*)malloc(currentSize * sizeof(P));
                     
                     for(int i = 0; i < currentSize; i++)
                     {
                        if(i != (currentSize - 1))     
                           (*this)[i] = temp[i];
                        else (*this)[i] = arg;
                     }
                     free((void*)temp);
                     return true;
                 }
                 else{
                     std::cout << "Could not store value at indice: "<< location;
                     std::cout << ". " << "\nCurrent size is: "<< currentSize << std::endl;
                     return false;
                 }
             };
             
             bool storeValue(P arg){//appends the value to the end of this prim array
                 P *temp = (P*)malloc(currentSize * sizeof(P));
                     
                 for(int i = 0; i < currentSize; i++)
                     temp[i] = (*this)[i];
                      
                 currentSize++;
                 free((void*)value);
                 value = (P*)malloc(currentSize * sizeof(P));
                     
                 for(int i = 0; i < currentSize; i++){
                    if(i != (currentSize - 1))     
                       (*this)[i] = temp[i];
                    else (*this)[i] = arg;
                 }
                 free((void*)temp);
                 return true;               
             }
             
             void trimToSize(int startRange = 0, int endRange){//trims this array
                if(startRange <= endRange && startRange >= 0 
                && endRange < currentSize){  
                  if(endRange <= 0 || startRange >= endRange){
                      clear();
                  }
                  else{
                      P *temp = (P*)malloc((endRange - startRange) * sizeof(P));
                      
                      for(int i = startRange; i < endRange; i++)
                              temp[i - startRange] = (*this)[i];
             
                      free((void*)value);
                      currentSize = (endRange - startRange);
                      value = (P*)malloc(currentSize * sizeof(P));
                      
                      for(int i = 0; i < currentSize; i++)
                              (*this)[i] = temp[i];
                              
                      free((void*)temp);
                  }
                }
                else{
                    std::cout << "Trim failed! ";
                    std::cout << "Current size is: "<< currentSize;
                    std::cout << std::endl;
                }                
             }
             
             void clear(){
                  free((void*)value);
                  
                  value = (P*)malloc(1 * sizeof(P));
                  currentSize = 1;
             }
             
             void displayContents(){
                  for(int i = 0; i < currentSize; i++){
                      if(i != (currentSize - 1))    
                        std::cout << (*this)[i] << ", ";
                      else std::cout << (*this)[i] << std::endl;
                  }
             };
             
             P &operator[](int arg){
                   P *temp = 0;
                   if(arg >= 0 && arg < currentSize)
                          return value[arg];
                   else
                   {
                       std::cout << "Index out of bounds!";
                       std::cout << "Could not access reference at location: ";
                       std::cout << arg << "!" << std::endl;
                       return *temp;
                   }         
             };
};

If I use the [] operator and return a reference, is there any way to mark that indice when a value is assigned to it?

Maybe you could use a bitset for tracking the assignments.
Two things I noticed:
- use of realloc() would result in fewer malloc/free calls
- you should test malloc's return value against NULL

Maybe you could use a bitset for tracking the assignments.
Two things I noticed:
- use of realloc() would result in fewer malloc/free calls
- you should test malloc's return value against NULL

I'm not well learned enough with realloc but I'll give it a shot.

Realloc's job is simply to add additional memory to an existing pointer, correct?

Edit: And I completely forgot that malloc could return 0 in some cases. Good call.

> If I use the [] operator and return a reference, is there any way to mark that indice when a value is assigned to it?
It's your class, you can do anything you want internally. :) Edward would probably store a complex type with bookkeeping information:

#include <iostream>
#include <stdexcept>

template <typename T>
class EdVector {
  struct Data {
    T _value;
    bool _isInitialized;

    Data(): _value(), _isInitialized(0) {}
    Data(T value): _value(value), _isInitialized(1) {}
  } *_src;
  int _size;
public:
  EdVector();
  EdVector(int startingSize);
  int Size() const;
  bool StoreValue(T value, int i);
  T& operator[](int i);
  const T& operator[](int i) const;
private:
  bool Resize(int size);
  T& GetValue(int i) const;
};

template <typename T>
EdVector<T>::EdVector(): _src(0), _size(0) {}

template <typename T>
EdVector<T>::EdVector(int startingSize)
  : _src(0), _size(0)
{
  if (!Resize(startingSize))
    throw std::runtime_error("Error initializing EdVector");
}

template <typename T>
int EdVector<T>::Size() const
{
  return _size;
}

template <typename T>
bool EdVector<T>::StoreValue(T value, int i)
{
  if (i < 0)
    throw std::range_error("Negative indexes are not allowed");

  if (i >= _size && !Resize(i + 1))
    return false;

  _src[i] = Data(value);
}

template <typename T>
T& EdVector<T>::operator[](int i)
{
  return GetValue(i);
}

template <typename T>
const T& EdVector<T>::operator[](int i) const
{
  return GetValue(i);
}

template <typename T>
bool EdVector<T>::Resize(int size)
{
  if (size < 0)
    return false;

  // Use new instead of realloc to guarantee
  // that constructors are called
  Data *temp = new Data[size];

  if (temp == 0)
    return false;

  for (int i = 0; i < _size; ++i)
    temp[i] = _src[i];

  // Only delete after the state is stable
  delete[] _src;
  _src = temp;
  _size = size;

  return true;
}

template <typename T>
T& EdVector<T>::GetValue(int i) const
{
  if (i < 0 || i >= _size)
    throw std::range_error("Index out of range");

  if (!_src[i]._isInitialized)
    throw std::runtime_error("Attempted use of uninitialized value");

  return _src[i]._value;
}

int main()
{
  EdVector<int> vec;

  for (int i = 0; i < 10; i++)
    vec.StoreValue(i, i * 2);

  for (int i = 0; i < vec.Size(); ++i) {
    try {
      std::cout << vec[i] << " at index " << i << '\n';
    } catch (...) {}
  }
}

> Realloc's job is simply to add additional memory to an existing pointer, correct?
realloc is dangerous in both C and C++. The problem that spans both languages is realloc is allowed to move the memory to a new address. Any other pointers you have into the old block may or may not be invalidated. Because you don't know, you have to assume that they're invalidated and the biggest benefit of realloc goes bye-bye. :(

A C++ specific problem is that realloc--malloc and calloc also--don't call constructors just like free doesn't call destructors. Your class is supposed to be for primitive types, but with operator overloading any class can be used as a primitive type. Those classes probably have all kinds of work done in constructors and destructors, so the C memory functions are a bad idea.

Wow I never thought of using a pointer-struct for each and every piece of data and holding an initializer. I'm not sure why but I couldn't think of something like that >_< .

After looking at nothing but code for the last few days my imagination slipped slightly so I couldn't think of anything like that...

and R.E. you cease to amaze me. Thanks a million!

> and R.E. you cease to amaze me.
Yes, Ed ceases to amaze on a regular basis. ;)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.