簡體   English   中英

c ++ operator =工作很奇怪(在函數內部輸出ok,但返回后錯誤..)

[英]c++ operator = working weird (output ok inside the function, but wrong after return..)

我有一個程序,我一直在修改以提取一些數據。
最近我做了另一個數據提取,並使用了解決方案,因為時間不夠。
現在,我試圖找出問題所在,因為我有一些空余時間。

下面是一個函數Act(),它是Mat類的成員函數,它形成一個具有改變數據值的新矩陣。 Mat有一個指向包含實際數據的緩沖區的指針。 我發現在返回Matrix的Act()函數之后,調用'operator ='函數。 (沒有'operator ='函數所以我添加了它。也許默認'=運算符'正在被使用。無論有沒有添加'operator ='函數,它都不會產生最終正確的輸出。這是部分的返回數據的'='運算符(類型為Mat)。(它是一個c ++代碼,但我只使用了printf,因為它無論如何都有效)

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,row = 128,col = 128
3be0 bbfc bbf5 3bf8 3af0 bbf6 bbef b29f bbaf 3bfd
3be0 bbfc bbf5 3bf8 3af0 bbf6 bbef b29f bbaf 3bfd

這個'3be0 bbfc bbf5 ......'是正確的模式。

調用部分看起來像這樣。

  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層已執行。
40de c2e2 c1eb 425e 3d4a c21b c187 b2b8 bfce 4358

如您所見,數據是錯誤的。
我能產生正確輸出的唯一方法是使用一個新對象並將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);   

原始代碼有什么問題?

operator =應該修改* this,而不是創建一個新的臨時對象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;
}

a = a.Act()不起作用,因為你已經錯誤地實現了operator= 默認operator=在這種情況下不起作用,因為您的類中有一個指針,並且當Act()返回的臨時值被銷毀時,它可能使指針無效。

operator=被調用,因為你在代碼中寫了= 當您使用“tmp work-around”時,您將創建一個新對象,該對象不會調用operator=而是復制構造函數。 這似乎有效。

至於如何正確實現operator= :賦值運算符應修改現有對象,而不是返回新對象。

例如:

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;
    }
};

當注釋正確陳述時, 賦值運算符旨在修改已存在的對象。 你正在創建一個新的並返回它。

嘗試這樣的事情:

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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM