Вопрос

Here is the code

#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;
}

After compile (g++ x.cpp) and run, I got the following results:

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)

I expect each Point to be destroyed twice, but they are destroyed three times instead. Why?

Это было полезно?

Решение

Because

Square(Point p1, Point p2)

takes arguments passed by value which creates a copy of the parameters you pass to it. So you have

  1. The original parameters
  2. The copies passed to the Square constructor
  3. The member variables of the instance of Square you create

3 instances.

Другие советы

you copy them into the constructor

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

results in

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

This constructor

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

accepts objects of type Point by value. So these temporary objects that created as parameters of the constructor are also deleted.

You could define the constructor the following way

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

to escape creating temporary objects during its call.

It is interesting to see the order in which destructors are called

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)

These two lines

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

mean that the compiler at first created the second argument Point(3, 4) and then the first argument Point( 1, 2 ). They are deleted in the reverse order.

These two lines

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

mean that at first data member upperleft was created because it declared before lowerright and then lowerright was created. Again they are deleted in the reverse order.

And at last these two lines

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

mean that at first Point( 1, 2 ) was created because it is defined before Point( 3, 4 ) in main and then Point( 3, 4 ) was created. They are deleted in the reverse order.

Destroy twice, using references:

#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;
}

Destroy once, using pointers:

#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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top