![](/img/trans.png)
[英]Why is it OK to return an object reference inside a function in c++?
[英]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.