代码之家  ›  专栏  ›  技术社区  ›  Chan Kim

C++操作符=工作怪异(输出函数内的函数,但返回后错误)。

  •  1
  • Chan Kim  · 技术社区  · 7 年前


    最近,我做了另一个数据提取,由于时间不够,我使用了一种变通方法。
    现在,我正试图找出问题所在,因为我有一些空闲时间。

    下面有一个函数Act(),它是Mat类的成员函数,它用更改的数据值形成一个新的矩阵。Mat有一个指向包含实际数据的缓冲区的指针。我发现在返回矩阵的Act()函数之后,调用了“operator=”函数。(没有操作符=)函数,所以我添加了它。也许默认的'=运算符'被使用。有或没有我的“操作符=”函数,它不产生最终的正确输出。这里是'='操作符返回数据(类型垫)的部分。(它是C++代码,但我只是使用了Prtff,因为它仍然有效)

    template<typename T>
    Mat<T> Mat<T>::operator = (const Mat<T>& rhs)
    {
      Mat<T> result(rhs.row_, rhs.col_);
      int num_bytes = sizeof(T) * rhs.row_ * rhs.col_;
      printf("ope = , res val = %x, src val = %x, row = %d, col = %d\n", result.val_, rhs.val_, rhs.row_, rhs.col_);
      for(int i=0;i<10;i++){
        printf("%04x ",((half_float::half *)rhs.val_)[i].data_);
        }
      printf("\n");
      memcpy(result.val_, rhs.val_, num_bytes);
      for(int i=0;i<10;i++){
        printf("%04x ",((half_float::half *)result.val_)[i].data_);
        }
      printf("\n");
      return result;
    }
    

    ope=,res val=12199b0,src val=c07680,行=128,列=128
    3be0 bbfc bbf5 3bf8 3af0 bbf6 BBF b29f bbaf 3bfd
    3be0 bbfc bbf5 3bf8 3af0 bbf6 BBF b29f bbaf 3bfd

      printf("calling activation..\n");
      d0_out = d0_out.Act(NN_CELL::AT_TANH);
      std::cout << "MLP Layer 0 executed." << std::endl;
      for(int i=0;i<10;i++){
        printf("%04x ",((half_float::half *)d0_out.val_)[i].data_);
        }
      printf("\n");
    

    但是在赋值之后,从主函数看,数据是奇怪的(在=操作符内部,复制似乎是正确的,但在外部,它不是)。

    执行MLP层0。


    生成正确输出的唯一方法是使用新对象并将Act()函数的结果赋给它。

    NN_CELL::Mat<T> d0_out1 = d0_out.Act(NN_CELL::AT_TANH); // tmp work-around  
    

    然后,d0_out1(新对象)包含正确的数据(3be0 bbfc bbf5..),而不是原始数据

    d0_out = d0_out.Act(NN_CELL::AT_TANH);   
    

    3 回复  |  直到 6 年前
        1
  •  1
  •   VLL Mohamed El-Nakeep    7 年前

    a = a.Act() 不起作用,因为您已实现 operator= 接线员= 在这种情况下不起作用,因为类中有指针,并且 Act() 如果已销毁,则可能会使指针无效。

    因为你写了 = 接线员= 但是复制构造函数。这似乎奏效了。

    接线员= 正确:赋值运算符应修改现有对象,而不是返回新对象。

    例如:

    struct A {
        int row_, col_;
        float *val_;
    
        A& operator=(const A& rhs) {
            if (this != &rhs) {
                const int num_bytes = sizeof(float) * rhs.row_ * rhs.col_;
                row_ = rhs.row_;
                col_ = rhs.col_;
                memcpy(val_, rhs.val_, num_bytes);
            }
            return *this;
        }
    };
    
        2
  •  1
  •   mcabreb    7 年前

    operator=应该修改*这个,而不是创建一个新的时态对象X,将接收到的数据复制到X,然后返回X。您已经创建了一个时态对象,但是运行operator=的类的数据没有被修改!

    请尝试以下代码:

    template<typename T>
    Mat<T> Mat<T>::operator = (const Mat<T>& rhs)
    {
      int num_bytes = sizeof(T) * rhs.row_ * rhs.col_;
      printf("ope = , res val = %x, src val = %x, row = %d, col = %d\n", this->val_, rhs.val_, rhs.row_, rhs.col_);
      for(int i=0;i<10;i++){
        printf("%04x ",((half_float::half *)rhs.val_)[i].data_);
        }
      printf("\n");
      memcpy(this->val_, rhs.val_, num_bytes);
      for(int i=0;i<10;i++){
        printf("%04x ",((half_float::half *)this->val_)[i].data_);
        }
      printf("\n");
      return *this;
    }
    
        3
  •  1
  •   Riom    7 年前

    Assignment Operator 用于修改已存在的对象。你正在创建一个新的并返回它。

    试着这样做:

    template<typename T>
    Mat<T>& Mat<T>::operator = (const Mat<T>& rhs)
    {
      row_ = rhs.row_;
      col_ = rhs.col_;
      delete val_;
      val_ = new T[row_*col_];
    
      int num_bytes = sizeof(T) * rhs.row_ * rhs.col_;
      printf("ope = , res val = %x, src val = %x, row = %d, col = %d\n", val_, rhs.val_, rhs.row_, rhs.col_);
      for(int i=0;i<10;i++){
        printf("%04x ",((half_float::half *)rhs.val_)[i].data_);
        }
      printf("\n");
      memcpy(val_, rhs.val_, num_bytes);
      for(int i=0;i<10;i++){
        printf("%04x ",((half_float::half *)val_)[i].data_);
        }
      printf("\n");
      return *this;
    }