代码之家  ›  专栏  ›  技术社区  ›  Jason R. Mick

如何定义双括号/双迭代器运算符,类似于向量的向量'?

  •  11
  • Jason R. Mick  · 技术社区  · 14 年前

    我移植的代码使用非常大的浮点数组,这可能会触发c到c++的malloc失败。我问了一个问题,我是否应该使用向量或deques和 Niki Yoshiuchi 慷慨地为我提供了一个安全包装类型的示例:

    template<typename T>
    class VectorDeque
    {
    private:
      enum TYPE { NONE, DEQUE, VECTOR };
      std::deque<T> m_d;
      std::vector<T> m_v;
      TYPE m_type;
      ...
    public:
      void resize(size_t n)
      {
        switch(m_type)
        {
          case NONE:
          try
          {
            m_v.resize(n);
            m_type = VECTOR;
          }
          catch(std::bad_alloc &ba)
          {
            m_d.resize(n);
            m_type = DEQUE;
          }
          break;
        }
      }
    };
    

    我需要一个2D vector of vectors/deque of deques,所以我将其修改为以下代码:

    template<typename T>
    class VectorDeque
    {
    private:
      enum STORAGE_CONTAINER { NONE, DEQUE, VECTOR };
      std::deque<std::deque<T> > x_d,y_d,z_d;
      std::vector<std::vector<T> > x_v,y_v,z_v;
      TYPE my_container;
    public:
      void resize(size_t num_atoms, size_t num_frames)
      {
        switch(m_type)
        {
          case NONE:
          try
          {
            x_v.resize(num_atoms);
     for (unsigned int couter=0;couter < num_frames; counter++)
       x_v[counter].resize(num_frames);
            y_v.resize(num_atoms);
     for (unsigned int couter=0;couter < num_frames; counter++)
       y_v[counter].resize(num_frames);
            z_v.resize(num_atoms);
     for (unsigned int couter=0;couter < num_frames; counter++)
       z_v[counter].resize(num_frames);
            my_container = VECTOR;
          }
          catch(std::bad_alloc &e)
          {
            x_d.resize(num_atoms);
     for (unsigned int couter=0;couter < num_frames; counter++)
       x_d[counter].resize(num_frames);
            y_d.resize(num_atoms);
     for (unsigned int couter=0;couter < num_frames; counter++)
       y_d[counter].resize(num_frames);
            z_d.resize(num_atoms);
     for (unsigned int couter=0;couter < num_frames; counter++)
       z_d[counter].resize(num_frames);
            my_container = DEQUE;
          }
          break;
        }
      }
    };
    

    x[1][2] 直接进入 真实的 我正在使用的内存容器(由枚举变量的值给定)。

    你怎么能使双支架过载?

    编辑1:

    基于Martin York/Matteo Italia的解决方案,我设计了以下课程:

    template<typename T>
    class VectorDeque2D
    {
    public:
    
      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 operator[](unsigned int first_index) { 
        return (*this, x);
      }
    
    
      void resize_first_index(unsigned int first_index) {
        try {
          my_vector.resize(first_index);
          my_container = VECTOR;
        }
        catch(std::bad_alloc &e) {
          my_deque.resize(first_index);
          my_container = DEQUE;
        }
      }
    
      void resize_second_index(unsigned int second_index) {
        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;
        }
      }
      void resize(unsigned int first_index,
              unsigned int second_index) {
        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;
        }    
      }
    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 x,int y) { 
        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;
      }
    
    };
    

    最后一个大小安全的2D容器!!谢谢你们!

    5 回复  |  直到 8 年前
        1
  •  20
  •   Loki Astari    14 年前

    主要有两种技术:

    1) 使用运算符()而不是运算符[]。

    class My2D
    {
        public:
           int&   operator()(int x,int y)  { return pget(x,y);}
        private:
           int&   pget(int x,int y) { /* retrieve data from 2D storage */ }
    };
    


    class My2D
    {
        public:
           class My2DRow
           {
               My2D& parent;
               int   x;
               public:
                   My2DRow(My2D& p, int theX) : parent(p), x(theX) {}     // Just init the temp object
                   int& operator[](int y)  const { return parent.pget(x,y);}   // Here we get the value.
           };
    
           // 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[]
           My2DRow operator[](int x)        { return My2DRow(*this, x);}
        private:
           friend class My2DRow;
           int&   pget(int x,int y) { /* retrieve data from 2D storage */ }
    };
    
    int main()
    {
        My2D   data;
        int&   val = data[1][2]; // works fine.
    
        // This is the same as
        My2D::My2DRow row  = data[1];
        int&          val2 = row[2]; 
    }
    

    我更喜欢第二种技术。

        2
  •  4
  •   Matteo Italia    14 年前
    你怎么能使双支架过载?

    例如,如果有一个向量向量,则工作已经完成: vector < vector < something > > 超载 operator[] vector< something > ;这反过来又使其括号运算符重载(并返回 something

    vector<vector<something> > vec;
    // ...
    something s = vec[2][3];
    


    代理对象示例:
    template <typename T>
    class Container
    {
    private:
        // ...
    
    
    public:
    
        // Proxy object used to provide the second brackets
        template <typename T>
        class OperatorBracketHelper
        {
            Container<T> & parent;
            size_t firstIndex;
        public:
            OperatorBracketHelper(Container<T> & Parent, size_t FirstIndex) : parent(Parent), firstIndex(FirstIndex) {}
    
            // This is the method called for the "second brackets"
            T & operator[](size_t SecondIndex)
            {
                // Call the parent GetElement method which will actually retrieve the element
                return parent.GetElement(firstIndex, SecondIndex);
            }
    
        }
    
        // This is the method called for the "first brackets"
        OperatorBracketHelper<T> operator[](size_t FirstIndex)
        {
            // Return a proxy object that "knows" to which container it has to ask the element
            // and which is the first index (specified in this call)
            return OperatorBracketHelper<T>(*this, FirstIndex);
        }
    
        T & GetElement(size_t FirstIndex, size_t SecondIndex)
        {
            // Here the actual element retrieval is done
            // ...
        }
    }
    

    (在适当的情况下添加重载的const方法:)

    请注意,使用此方法,对于一个 operator() 实现,因为检索仍然在一个地方完成,对两个索引的使用没有限制,在执行检索时有两个索引,并且不返回“fat”临时对象( OperatorBracketHelper 与两个指针一样大,并且可以很容易地被编译器优化掉)。

        3
  •  2
  •   Mark Ransom    14 年前

    C++中没有“双括号”操作符。你需要做的是定义一个 [] 运算符,并让它返回对另一个对象的引用,而该对象又可以响应自己的对象 [] 接线员。可以根据需要嵌套多个层次。

    [] 外向量上的运算符返回对其中一个内向量的引用 运算符返回对向量的单个元素的引用。

    std::vector<std::vector<float> > example;
    std::vector<float> & first = example[0];  // the first level returns a reference to a vector
    float & second = example[0][0];  // the same as first[0]
    
        4
  •  1
  •   Thomas Matthews    14 年前

    别让汽车超载 [] ()

    请参见此链接: Overloading Subscript Operator.

    我强烈建议在发布到堆栈溢出之前,先阅读C++ FAQ Lite至少一次。此外,搜索堆栈溢出也可能产生一些有用的信息。

        5
  •  0
  •   Community CDub    8 年前

    我在一个例子中讨论了多维数组的重载操作符[] answer to a previous question .