2

我写了一个简单的向量类,它重载了赋值和加法运算符。该代码将两个向量相加,并在相加前后打印向量。令人惊讶的是,在 c=a+b 行之后调用了析构函数 ~MyVector()。我不明白为什么会这样,因为对象 a、b 和 c 都没有超出范围。您了解调用析构函数的原因吗?

#include<iostream>
#include<cstdlib>

using namespace std;

template<typename T>
class MyVector
{
  public:

  MyVector(int s)
  {
    size=s;
    a=new T[s];
  }

  ~MyVector()
  {
    delete[] a;
    size=0;
  };

  void freeVec()
  {
    cout<<"Calling destructor. a[0]= "<<a[0]<<endl;
    if(a!=NULL)
    {
      free(a);
      a=NULL;
    }
  }

  int getSize(void)
  {
    return size;
  }
  void setSize(int ss)
  {
    size=ss;
  }
  T &operator[](int i)
  {
    return a[i];
  }

  MyVector &operator=(MyVector mv)
  {
    if(this==&mv)
      return *this;
    for(int i=0;i<mv.getSize();i++)
      this->a[i]=mv[i];
    this->size=mv.getSize();
    return *this;
  }

  MyVector operator+(MyVector &mv)
  {
    for(int i=0;i<size;i++)
    {
      this->a[i]+=mv[i];
    }
    cout<<endl;
    return *this;
  }

  private:
  int size;
  T *a;
};

int main(void)
{
  MyVector<int> a(3),b(3),c(3);

  a[0]=1;a[1]=2;a[2]=3;
  b[0]=4;b[1]=5;b[2]=6;
  cout<<"initial vector"<<endl;
  for(int i=0;i<3;i++)
    cout<<a[i]<<"  ";
  cout<<endl;
  for(int i=0;i<3;i++)
    cout<<b[i]<<"  ";
  cout<<endl;

  c=a+b;  

  cout<<"final vectors"<<endl;
  for(int i=0;i<3;i++)
    cout<<a[i]<<"  ";
  cout<<endl;
  for(int i=0;i<3;i++)
    cout<<b[i]<<"  ";
  cout<<endl;
  for(int i=0;i<3;i++)
    cout<<c[i]<<"  ";
  cout<<endl;

  cout<<endl;
  return 0;
}
4

3 回答 3

7

a + b返回一个无名的临时对象,该对象随后被复制到c(通过赋值运算符)然后被破坏。这就是您看到的析构函数调用。

此外,您的赋值运算符按值接收它的参数(为什么???),这意味着理论上也可以为此创建另一个副本。您的编译器显然优化了该副本,这就是为什么您只看到一个额外的析构函数调用。

顺便说一句,由于您手动管理对象中分配的内存,因此根据“三规则”实现复制构造函数也是一个非常好的主意。当前版本的类(没有复制构造函数)可以很容易地用于构建损坏的代码,特别是因为缺少复制构造函数。实际上,您当前的代码已经损坏,因为它使用编译器提供的复制构造函数来复制您的类对象。您没有看到任何崩溃的唯一原因是编译器优化(省略)了大多数副本,并且可能是因为您很幸运。

最重要的是,您的二进制实现+修改了存储在*this对象中的数据(为什么???),这意味着c = a + b修改a. 这并不是人们期望看到的二元+运算符的典型行为。

您的代码中还有许多其他奇怪的东西。例如,什么是freeVec以及为什么要尝试free在始终由 分配的内存上使用new[]?另外,为什么析构函数设置size0?那有什么意义呢?

于 2013-08-22T20:00:40.237 回答
3

因为您MyVector operator+(MyVector &mv)创建了一个副本(应该这样做)。此临时副本一旦存储在c.

请注意,修改this不是operastor+一个好计划。您不希望成为与froma相同的值。cc = a + b;

于 2013-08-22T20:01:56.407 回答
0

在该行c = a + b;中实际上有 2 个操作。首先是加法。他们实现它的方式,a实际上增加了b. a然后在该行中返回的副本return *this;。此副本尚未分配给c; 这是一个无名的暂时。

在赋值调用中,这个副本按值传递,从而创建另一个副本。但是,通过复制省略,我相信第二个副本可能会被优化,因此总共创建了 1 个副本。因此赋值运算符的输入是一个对象的副本。当赋值运算符返回时,该对象将被销毁。

与您的问题有些正交,我想指出您实施运算符的方式存在许多问题。首先,您的+操作员正在修改与之关联的对象。在该行c = a + b;中,由于您的函数中的行,值a会被修改this->a[i]+=mv[i];,我认为这不是您的预期效果。

其次,在您实施=运算符时,这些行

if(this==&mv)
  return *this;

是无用的,因为 mv 是按值传递的,并且永远不会有相同的地址this

于 2013-08-22T20:10:49.273 回答