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

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

#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。上面的 operator+ 是如何工作的?我感到困惑的是,与 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

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

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

如果您使用 std::vector<T> 而不是 C-array ptr 并且它的大小 numElem.

,您就不会遇到这样的错误

What I'm confused is that as opposed to Java, in C++ Box box creates an object on the stack, but the method is returning the object whose lifetime is limited to that scope of method (operator).

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

正确,但这不是问题,因为该对象是复制的Box 对象定义了一个隐式默认值 "copy constructor"(带有签名 Box (Box const & b))和一个隐式 operator=()(带有签名 Box & (Box const & b))。从 C++11 开始,也一个"move constructor"(带有签名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,默认的 copy/move 构造函数和 operator=() 都可以,因为不涉及内存分配或其他复杂操作(它们只是复制 length , breadth, height).

问题出在你的 SmartPointer 上(如果我理解正确的话)动态分配的内存(对于 ptr)。

默认构造函数(等)不再正常,因为它复制ptr的值,即(破坏临时对象)立即释放(如果您在 ~SmartPointer().

中添加了 delete[]

结果是当你写

SmartPointer<int> sPointer8 = sPointer6 + sPointer7;

sPointer8中的ptr指向空闲的内存区域。并且该程序可以用于其他目的(其他变量)。

So, when you get

1310912
1338712
24

这是因为(我想)在临时 sPointer6 + sPointer7 中为 result[0]result[1] 保留的内存是空闲的,并且可以重新用于一个或多个其他变量。

您从

中得到不同的结果
    SmartPointer<T> result(tempArray, pSize);
    return result;

来自

    return SmartPointer<T>(tempArray, pSize);

这纯粹是致命的,因为在这两种情况下,您都在访问空闲内存,在这两种情况下,都是 UB(未定义的行为)。

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

解决方案:编写copy/move构造函数,同时operator=()来管理在ptr.

中分配的内存的复制和复制

或者,更好的是,避免直接管理内存并使用标准库中可用的 containers/smart 指针。

还有一点:

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

不是(标准 C++):您不能用 run-time 值初始化 C-style 数组。