代码之家  ›  专栏  ›  技术社区  ›  Giogre

在C中构建SquareMatrix模板类的问题++

  •  0
  • Giogre  · 技术社区  · 5 年前

    我试图建立一个 SquareMatrix 通过使用接受4个参数作为4个子矩阵的构造函数来创建模板类 a , b , c , d 占据四个象限( =西北, b =东北, c =西南, d =东南)。如下所示:

        template<class T> class SquareMatrix {
        public:
            SquareMatrix(){}
            SquareMatrix(const T first, const T second, const T third, const T fourth) {
                a = first;
                b = second;
                c = third;
                d = fourth;
            }
            SquareMatrix<T>(const SquareMatrix<T>& rhs) { // copy constructor
                a = rhs.getA();
                b = rhs.getB();
                c = rhs.getC();
                d = rhs.getD();
            }
            SquareMatrix& operator=(const SquareMatrix rhs) {  // assignment operator
                if (&rhs != this) {
                    SquareMatrix(rhs);
                }
    
                return *this;
            }
            ~SquareMatrix() {}  // destructor
    
            // getters and setters
            T getA() const {return a;}
            T getB() const {return b;}
            T getC() const {return c;}
            T getD() const {return d;}
            void setA(const T& input) {a = input;}
            void setB(const T& input) {b = input;}
            void setC(const T& input) {c = input;}
            void setD(const T& input) {d = input;}
    
        private:   
            // 4 quadrants
            // [a, b;
            //  c, d]
            T a, b, c, d;
        };
    
        template<class T> SquareMatrix<T> operator+(const SquareMatrix<T> lhs, 
                          const SquareMatrix<T>& rhs) {
            SquareMatrix<T> ret(lhs);
            ret.setA( ret.getA() + rhs.getA() );
            ret.setB( ret.getB() + rhs.getB() );
            ret.setC( ret.getC() + rhs.getC() );
            ret.setD( ret.getD() + rhs.getD() );
    
            return ret;
        };
        template<class T> SquareMatrix<T> operator-(const SquareMatrix<T> lhs,
                          const SquareMatrix<T>& rhs) {
            SquareMatrix<T> ret(lhs);
            ret.setA( ret.getA() - rhs.getA() );
            ret.setB( ret.getB() - rhs.getB() );
            ret.setC( ret.getC() - rhs.getC() );
            ret.setD( ret.getD() - rhs.getD() );
    
            return ret;
        };
        // this is the implementation of Strassen's algorithm
        template<class T> SquareMatrix<T> operator*(const SquareMatrix<T>& lhs, 
                          const SquareMatrix<T>& rhs) {
            T product_1 = lhs.getA() * ( rhs.getB() - rhs.getD() );
            T product_2 = ( lhs.getA() + lhs.getB() ) * rhs.getD();
            T product_3 = ( lhs.getC() + lhs.getD() ) * rhs.getA();
            T product_4 = lhs.getD() * ( rhs.getC() - rhs.getA() );
            T product_5 = ( lhs.getA() + lhs.getD() ) * ( rhs.getA() + rhs.getD() );
            T product_6 = ( lhs.getB() - lhs.getD() ) * ( rhs.getC() + rhs.getD() );
            T product_7 = ( lhs.getA() - lhs.getC() ) * ( rhs.getA() + rhs.getB() );
            SquareMatrix<T> ret;
            ret.setA(product_5 + product_4 - product_2 + product_6);
            ret.setB(product_1 + product_2);
            ret.setC(product_3 + product_4);
            ret.setD(product_1 + product_5 - product_3 - product_7);
    
            return ret;
        };
    

    现在,我试图通过以下操作创建一个嵌套的4x4矩阵:

        int main() {
            cout << "Example: a 4x4 matrix: " << endl;
            // 4 single quadrants 
            SquareMatrix<int> M_1A(1, 2, 3, 4);
            SquareMatrix<int> M_1B(5, 6, 7, 8);
            SquareMatrix<int> M_1C(9, 10, 11, 12);
            SquareMatrix<int> M_1D(13, 14, 15, 16);
            // 4x4 matrix M_1
            SquareMatrix< SquareMatrix<int> > M_1(M_1A, M_1B, M_1C, M_1D);
            // test
            cout << "test: " << endl;
            cout << M_1.getA().getA() << endl;
    
            return 0;
        }
    

    预期的矩阵输出应为 M_1 = [1,2,5,6; 3,4,7,8; 9,10,13,14; 11,12,15,16] . 我用 M_1.getA().getA() 首次访问命令 M_1A 然后访问 1 嵌套在里面,但输出显示一个不断变化的大数字,也许是一个地址?(上次我尝试时,结果为6684672)。 是否有方法以这种方式实现矩阵类?

    (编辑:现在包括赋值运算符和析构函数,可能是错误的来源)

    0 回复  |  直到 5 年前
        1
  •  1
  •   PaulMcKenzie    5 年前

    正如评论所暗示的那样,是赋值运算符出了问题。

    SquareMatrix& operator=(const SquareMatrix rhs) {
        if (&rhs != this) {
             SquareMatrix(rhs); // <-- This creates a temporary that 
                                // dies off after that line is executed
        }
        return *this;
    }
    

    赋值运算符不执行任何赋值操作。相反,这是一个暂时的 SquareMatrix 是制造的。

    要解决此问题,请执行以下操作之一

    1) 不提供任何赋值运算符、复制构造函数或析构函数,因为类型 T 应该可以安全地复制。

    2) 修复赋值运算符,使其正常工作:

    #include <algorithm>
    //...
    SquareMatrix& operator=(const SquareMatrix rhs) {
        if (&rhs != this) {
             SquareMatrix t(rhs); 
             std::swap(t.a, a); 
             std::swap(t.b, b); 
             std::swap(t.c, c); 
             std::swap(t.d, d); 
        }
        return *this;
    }
    

    现在作业开始了。然而,我建议不要编写不需要编写的代码,你的错误实现就是一个很好的例子。

    在您的情况下,如果您让编译器生成赋值运算符和/或依赖 T 在模板中,如果具有正确的复制语义,您的类就会正常工作。

        2
  •  1
  •   Andreas_75    5 年前

    Paul的评论是正确的。虽然你的SquareMatrix不是内置的,但它被声明为由4个T类型的元素组成。你的类的默认副本c'tor将使用T在你的用法中表示的实际类型的赋值运算符或赋值c'tor。

    我有一些改进代码的建议:

    1. 如果T是一个内存占用大于指针/int的类型:让你的c'tor接收元素bij const引用会更有效,如下所示:
        SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
    
    1. 尽可能多地使用复制构造函数:这样四个元素就不会先初始化,然后再赋值。相反,它们会立即用正确的值进行初始化。
         SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
         : a( _a), b( _b), c( _c), d( _d)
         { /* empty body */ }
    
    1. 明智地选择你的名字,以简化事情。在不必的情况下,不要在名称方案中引入额外的映射;它只会创造滑倒的机会。我已经在上面的第1点中应用了它:-)。
    2. 不要“一厢情愿地编程”:在注释或类型/变量名中写下某物应该是某物,这并不会让它成为那样。在你的例子中:你的类不是方阵,甚至不是矩阵。对编译器来说,它是一种数据类型,由四个元素组成,分别命名为a、b、c和d,类型为T,在编译时定义。