Question

Bear with me because I'm self taught in C++ and am spending my limited extra time on the job to try to learn more about it (I'm a chemical engineering researcher by day).

I have a pretty simple objective: 1. Make a size-safe container to store a long list of floats. 2. Make a specialized version of that container that acts as a matrix.

What I've come up with thus far, based on some feedback on various questions I've posed here is:

template<typename T>
class VectorDeque
{
public:

  void resize_index(unsigned int index) {
    if ( my_container == VECTOR ) {
      try {
        my_vector.resize(index);
        my_container = VECTOR;
      }
      catch(std::bad_alloc &e) {
        my_deque.resize(index);
        my_container = DEQUE;
      }
    }
    else if ( my_container == DEQUE ) {
      my_deque.resize(index);
    }
  }

  T operator[](unsigned int index) { 
    T ret_val;
    if ( STORAGE_CONTAINER == VECTOR ) {
      ret_val = my_vector[index];
    }
    else if ( STORAGE_CONTAINER == DEQUE ) {
      ret_val = my_deque[index];
      }
  }
private:
  enum STORAGE_CONTAINER { NONE, DEQUE, VECTOR };

  std::vector<T> my_vector;
  std::deque<T> my_deque;
  STORAGE_CONTAINER my_container;

  T& get(int index) { 
    T temp_val;
    if(my_container == VECTOR) {
      temp_val = my_vector[index];
    }
    else if(my_container == DEQUE) {
      temp_val = my_deque[index];
    }

    return temp_val;
  }

};

template<typename T>
class VectorDeque2D: public VectorDeque<T>
{
public:

  template<typename T>
  class VectorDeque2D_Inner_Set
  {
    VectorDeque2D& parent;
    int   first_index;
  public:
    // Just init the temp object
    VectorDeque2D_Inner_Set(My2D& p, int first_Index) : 
      parent(p), 
      first_Index(first_index) {} 
    // Here we get the value.
    T& operator[](int second_index)  const 
    { return parent.get(first_index,second_index);}   
  };

  // Return an object that defines its own operator[] that will access the data.
  // The temp object is very trivial and just allows access to the data via 
  // operator[]
  VectorDeque2D_Inner_Set<T> operator[](unsigned int first_index) { 
    return  VectorDeque2D_Inner_Set<T>(*this, first_index);
  }

  void resize_index_second(unsigned int second_index) {
    if ( my_container == VECTOR ) {
      try {
        for (unsigned int couter=0;couter < my_vector.size(); counter++) {
          my_vector[counter].resize(second_index);
        }
        my_container = VECTOR;
      }
      catch(std::bad_alloc &e) {
        for (unsigned int couter=0;couter < my_deque.size(); counter++) {
          my_deque[counter].resize(second_index);
        }
        my_container = DEQUE;
      }
    }
    else if ( my_container == DEQUE ) {
      for (unsigned int couter=0;couter < my_deque.size(); counter++) {
        my_deque[counter].resize(second_index);
      }
    }
  }

  void resize(unsigned int first_index,
          unsigned int second_index) {
    if ( my_container == VECTOR ) {
      try {
        my_vector.resize(first_index);
        for (unsigned int couter=0;couter < my_vector.size(); counter++) {
          my_vector[counter].resize(second_index);
        }
        my_container = VECTOR;
      }
      catch(std::bad_alloc &e) {
        my_deque.resize(first_index);
        for (unsigned int couter=0;couter < my_deque.size(); counter++) {
          my_deque[counter].resize(second_index);
        }
        my_container = DEQUE;
      }    
    }
    else if ( my_container == DEQUE ) {
      my_deque.resize(first_index);
      for (unsigned int couter=0;couter < my_deque.size(); counter++) {
        my_deque[counter].resize(second_index);
      }
    }
  }
private:
  enum STORAGE_CONTAINER { NONE, DEQUE, VECTOR };

  friend class VectorDeque2D_Inner_Set;

  std::vector<std::vector<T> > my_vector;
  std::deque<std::deque<T> > my_deque;
  STORAGE_CONTAINER my_container;

  T& get(int first_index,int second_index) { 
    T temp_val;
    if(my_container == VECTOR) {
      temp_val = my_vector[first_index][second_index];
    }
    else if(my_container == DEQUE) {
      temp_val = my_deque[first_index][second_index];
    }

    return temp_val;
  }

};

With this implementation I tried to:
1. Present the user of the wrapper with two options for access (".get(x,y)" and "[x][y]")
2. Maximize reuse by having a based wrapped class and then inheriting it to make the matrix.
3. Solve the problem of transitioning from a vector to a deque if the continuous memory limit is hit.

Does this seem like a decent solution? Suggestions?

Was it helpful?

Solution

Have you looked at Boost::Matrix? There's a lot of numeric and linear algebra things already built within that library.

EDIT:

After reading your comment about transitioning from a vector to a deque when size limits are reached, go with deque. Getting "fancy" like that is slowing your productivity down. Focus on the problem at hand and let the collection worry about the memory. Deque is quite fast for large arrays and only suffers when you release memory in comparison to vector.

OTHER TIPS

Transitioning between the two during a single usage seems unlikely to be worth the effort, to me.

If you want to do this via roll your own, you could define a second template parameter that allows the container type to be specified at compile-time. Then you would not need both vector and deque as members and the type switching code goes away.

template<typename T, typename CONTAINER>
class VectorDeque
{
// snip
private:
  CONTAINER<T> _storage;
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top