Оператор c ++ = работает странно (вывод нормально внутри функции, но не верен после возврата ..) - PullRequest
0 голосов
/ 23 января 2019

У меня есть программа, которую я модифицировал для извлечения некоторых данных.
Недавно я сделал еще одно извлечение данных и использовал обходной путь из-за нехватки времени.
Теперь я пытаюсь найти, чтопроблема была, потому что у меня есть немного свободного времени.

Ниже представлена ​​функция Act (), которая является функцией-членом класса Mat, и она формирует новую матрицу с измененными значениями данных.Мат имеет указатель на буфер, содержащий фактические данные.Я обнаружил, что после функции Act (), которая возвращает матрицу, вызывается функция operator =.(не было никакой функции '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, строка = 128, col = 128
3be0 bbfc bbf5 3bf8 3af0 bbf6 bbef b29f bbaf 3bfd
3be0 bbfc bbf5 3bf8 3af0 bbf6 bbef b29f bbaf 3bfd

1010это правильный шаблон.

Вызывающая часть выглядит следующим образом.

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

Что не так с исходным кодом?

Ответы [ 3 ]

0 голосов
/ 23 января 2019

a = a.Act() не работает, потому что вы ввели operator= неправильно. Значение по умолчанию operator= в этом случае не работает, поскольку в вашем классе есть указатель, а когда временное значение, возвращаемое Act(), уничтожено, оно, вероятно, лишает законной силы указатель.

operator= называется, потому что вы написали = в своем коде. Когда вы используете «обходной путь tmp», вы создаете новый объект, который вызывает не 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;
    }
};
0 голосов
/ 23 января 2019

Если комментарии правильно указаны, оператор присваивания предназначен для изменения уже существующего объекта. Вы создаете новый и возвращаете его.

Попробуйте что-то вроде этого:

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;
}
0 голосов
/ 23 января 2019

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...