运算符方法和返回对象"out-of-scope"?

operator method and returning "out-of-scope" object?

本文关键字:out-of-scope 对象 返回 方法 运算符      更新时间:2023-10-16
#include <iostream>
using namespace std;
class Box {
public:
double getVolume(void) {
return length * breadth * height;
}
void setLength( double len ) {
length = len;
}
void setBreadth( double bre ) {
breadth = bre;
}
void setHeight( double hei ) {
height = hei;
}
// Overload + operator to add two Box objects.
Box operator+(const Box& b) {
Box box; //local object?
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
private:
double length;      // Length of a box
double breadth;     // Breadth of a box
double height;      // Height of a box
};

代码的来源:https://www.tutorialspoint.com/cplusplus/cpp_overloading.htm.以上运算符+是如何工作的?我感到困惑的是,与Java相反,在C++Box中,Box在堆栈上创建了一个对象,但该方法返回的对象的生存期仅限于该方法(运算符)的范围。

所以我尝试了另一个例子:

template <typename T>
class SmartPointer
{
T *ptr;
int numElem; //-1 if an element. >=0 if an array
public:
SmartPointer(T pNum);
SmartPointer();
SmartPointer(T *pArray, int pSize);
~SmartPointer();
SmartPointer(std::initializer_list<T> nums);
T getValue() const;
T getValue(int index) const;
void setValue(T pNum);
void setValue(T pNum, int index);
int getNumElem() const;
SmartPointer<T> operator+ (const SmartPointer<T>& ptr);
SmartPointer<T> operator- (const SmartPointer<T>& ptr);
SmartPointer<T> operator* (const SmartPointer<T>& ptr);
};
template <class T>
SmartPointer<T> SmartPointer<T>::operator+ (const SmartPointer<T>& p_ptr)
{
int pSize = this->getNumElem();
T tempArray[pSize] = {0};
for(int i = 0; i < this->getNumElem(); i++)
{
int result = this->getValue(i) + p_ptr.getValue(i);
tempArray[i] = result;
}
SmartPointer<T> result(tempArray, pSize); (line 60)
return result; (line 61)
}
}

我正在尝试实现smartpointer,我想重载+,就好像它是一个组件加法(像向量加法)一样。

然后,如果我运行以下代码:

SmartPointer<int> sPointer6({10,11,12});
SmartPointer<int> sPointer7({10,11,12});
SmartPointer<int> sPointer8 = sPointer6 + sPointer7;
cout << sPointer8.getValue(0) << endl; //getValue(index)
cout << sPointer8.getValue(1) << endl;
cout << sPointer8.getValue(2) << endl;

我得到以下输出:

1310912
1338712
24

但如果我用替换60号线和61号线

return SmartPointer<T>(tempArray, pSize);

然后我得到以下输出:

20
22
24

为什么我得到不同的输出?为什么第一个示例有效,而智能指针示例无效?

我感到困惑的是,与Java相反,在C++Box中,Box在堆栈上创建了一个对象,但该方法返回的对象的生存期仅限于该方法(运算符)的范围。

Box operator+(const Box& b) {
Box box; //local object?
// ...
return box;
}

正确,但这不是问题,因为对象被复制了。Box对象定义了一个隐式默认"复制构造函数"(具有签名Box (Box const & b))和一个隐式operator=()(具有签名Box & (Box const & b))。从C++11开始,还有一个"移动构造函数"(带有签名Box (Box && b))和Box & operator=(Box const & b)

所以,当你写时

Box a, b, c;
// ...
Box d { a + b };
c = a + b;

operator+()创建临时Box(result),在d中,通过复制或移动构造函数,或在c中,通过operator=(),在其被销毁之前,将其复制(或移动)。

对于Box,默认的复制/移动构造函数和operator=()是可以的,因为不涉及内存分配或其他复杂操作(它们只是复制lengthbreadthheight)。

您的SmartPointer(如果我理解正确的话)出现了动态分配内存(用于ptr)的问题。

默认构造函数(等)不再正常,因为它复制立即解除分配的ptr的值(破坏临时对象)(如果您在~SmartPointer()中添加了delete[])。

结果是,当你写时

SmartPointer<int> sPointer8 = sPointer6 + sPointer7;

CCD_ 24中的CCD_。程序可以用于其他目的(其他变量)。

So, when you get
1310912
1338712
24

这是因为(我想)在临时CCD_ 27中为CCD_ 25和CCD_。

事实上,你从中得到了不同的结果

SmartPointer<T> result(tempArray, pSize);
return result;

return SmartPointer<T>(tempArray, pSize);

这是一个纯粹的死亡,因为在这两种情况下,你都在访问空闲内存,即UB(Undefined Bahaviour)。

UB的意思是:任何事情都有可能发生。

解决方案:写复制/移动构造函数,同时写operator=()来管理ptr中分配的内存的复制和拷贝。

或者,最好避免直接管理内存,使用标准库中可用的容器/智能指针。

另一点:

int pSize = this->getNumElem();
T tempArray[pSize] = {0};

is not(标准C++):不能用运行时值初始化C样式数组。

您的模板类SmartPointer没有定义operator=和复制构造函数,因此定义了默认的operator=或复制构造函数。返回的副本sPointer8引用了释放的数组ptr。这是UB,它是由于违反了自由的规则。

如果使用std::vector<T>而不是C阵列ptr及其大小numElem,则不会出现这样的错误。