【问题标题】:Why are these points destroyed three times?为什么这些点被破坏了三遍?
【发布时间】:2014-01-30 14:18:33
【问题描述】:

这里是代码

#include <iostream>
#include <stdio.h>
using namespace std;

class Point {
    private:
        int x;
        int y;
    public:
        Point(int x, int y) : x(x), y(y) {}
        ~Point() {
            printf("Point destroyed: (%d, %d)\n", x, y);
        }
};

class Square {
    private:
        Point upperleft;
        Point lowerright;
    public:
        Square(int x1, int y1, int x2, int y2) : upperleft(x1, y1), lowerright(x2, y2) {}
        Square(Point p1, Point p2) : upperleft(p1), lowerright(p2) {}
        ~Square() {
            printf("Square destroyed.\n");
        }
};

int main(int argc, char const* argv[])
{
    Point p1(1, 2);
    Point p2(3, 4);
    Square s1(p1, p2);
    return 0;
}

编译(g++ x.cpp)运行后,得到如下结果:

Point destroyed: (1, 2)
Point destroyed: (3, 4)
Square destroyed.
Point destroyed: (3, 4)
Point destroyed: (1, 2)
Point destroyed: (3, 4)
Point destroyed: (1, 2)

我希望每个点被摧毁两次,但它们被摧毁了三次。为什么?

【问题讨论】:

  • 什么编译器和什么选项?
  • p1 和 p2 将被销毁,将它们传递给 Square 构造函数时生成的副本以及从这些副本构造数据成员时生成的第二对副本也会被销毁。
  • @JohnZwinck 请查看编辑。
  • 如何通过它们而不构建新的?通过引用?

标签: c++ destroy


【解决方案1】:

因为

Square(Point p1, Point p2)

接受按值传递的参数,这会创建您传递给它的参数的副本。所以你有

  1. 原始参数
  2. 传递给Square构造函数的副本
  3. 你创建的Square实例的成员变量

3 个实例。

【讨论】:

  • 所以一共有两个副本,为什么要销毁3次?
  • @qed 当您将参数按值传递给函数时,原始参数会生成临时副本。
  • @qed 三份:main函数中的原件,通过值传递给构造函数的副本,以及Square成员变量。
【解决方案2】:

你将它们复制到构造函数中

试试Square(const Point&amp; p1,const Point&amp; p2) : upperleft(p1), lowerright(p2) {}

结果

Square destroyed.
Point destroyed: (3, 4)
Point destroyed: (1, 2)
Point destroyed: (3, 4)
Point destroyed: (1, 2)

【讨论】:

    【解决方案3】:

    这个构造函数

    Square(Point p1, Point p2) : upperleft(p1), lowerright(p2) {}
    

    按值接受 Point 类型的对象。所以这些作为构造函数参数创建的临时对象也被删除了。

    您可以通过以下方式定义构造函数

    Square( const Point &p1, const Point &p2) : upperleft(p1), lowerright(p2) {}
    

    在调用期间避免创建临时对象。

    看看析构函数的调用顺序很有趣

    Point destroyed: (1, 2)
    Point destroyed: (3, 4)
    Square destroyed.
    Point destroyed: (3, 4)
    Point destroyed: (1, 2)
    Point destroyed: (3, 4)
    Point destroyed: (1, 2)
    

    这两行

    Point destroyed: (1, 2)
    Point destroyed: (3, 4)
    

    意味着编译器首先创建了第二个参数 Point(3, 4),然后创建了第一个参数 Point(1, 2)。它们以相反的顺序被删除。

    这两行

    Point destroyed: (3, 4)
    Point destroyed: (1, 2)
    

    意味着首先创建了数据成员upperleft,因为它在lowerright之前声明,然后创建了lowerright。再次以相反的顺序删除它们。

    最后是这两行

    Point destroyed: (3, 4)
    Point destroyed: (1, 2)
    

    表示首先创建了 Point(1, 2),因为它是在 main 中的 Point(3, 4) 之前定义的,然后创建了 Point(3, 4)。它们以相反的顺序被删除。

    【讨论】:

      【解决方案4】:

      使用引用销毁两次:

      #include <iostream>
      #include <stdio.h>
      using namespace std;
      
      class Point {
          private:
              int x;
              int y;
          public:
              Point(int x, int y) : x(x), y(y) {}
              ~Point() {
                  printf("Point destroyed: (%d, %d)\n", x, y);
              }
      };
      
      class Square {
          private:
              Point upperleft;
              Point lowerright;
          public:
              Square(int x1, int y1, int x2, int y2) : upperleft(x1, y1), lowerright(x2, y2) {}
              Square(Point& p1, Point& p2) : upperleft(p1), lowerright(p2) {}
              ~Square() {
                  printf("Square destroyed.\n");
              }
      };
      
      int main(int argc, char const* argv[])
      {
          Point p1(1, 2);
          Point p2(3, 4);
          Square s1(p1, p2);
          return 0;
      }
      

      使用指针销毁一次:

      #include <iostream>
      #include <stdio.h>
      using namespace std;
      
      class Point {
          private:
              int x;
              int y;
          public:
              Point(int x, int y) : x(x), y(y) {}
              ~Point() {
                  printf("Point destroyed: (%d, %d)\n", x, y);
              }
      };
      
      class Square {
          private:
              Point* upperleft;
              Point* lowerright;
          public:
              Square(int x1, int y1, int x2, int y2) {
                  Point* ul = new Point(x1, y1);
                  Point* lr = new Point(x2, y2);
                  upperleft = ul;
                  lowerright = lr;
              }
              Square(Point* p1, Point* p2) : upperleft(p1), lowerright(p2) {}
              ~Square() {
                  printf("Square destroyed.\n");
              }
      };
      
      int main(int argc, char const* argv[])
      {
          Point p1(1, 2);
          Point p2(3, 4);
          Square s1(&p1, &p2);
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-04-30
        • 1970-01-01
        • 1970-01-01
        • 2019-02-08
        • 1970-01-01
        • 2011-12-05
        • 1970-01-01
        相关资源
        最近更新 更多