Управление памятью в C ++ - PullRequest
       52

Управление памятью в C ++

0 голосов
/ 03 сентября 2018

Я пытаюсь проверить, как и где данные расположены и уничтожены. Для примера кода ниже:

  1. Новая точка создается и возвращается методом NewCartesian. Я знаю, что он должен храниться в куче. Когда он перемещается обратно в вектор, копируется ли память содержимого точек в новую структуру точек? Или он хранится в качестве ссылки на этот указатель?

  2. Когда точка создана, когда она уничтожена? Нужно ли уничтожать очки, когда я закончу с этим? Или они уничтожены, когда они больше не нужны? Например, если бы main была другой функцией, вектор не был бы полезен, когда закончил.

  3. В зависимости от приведенных выше ответов, когда полезно использовать ссылку на объекты? Должен ли я использовать Point & p или Point p для возврата Point :: NewCartesian?

    #define _USE_MATH_DEFINES
    
    #include <iostream>
    #include <cmath>
    
    using namespace std;
    
    struct Point {
    private:
      Point(float x, float y) : x(x), y(y) {}
    
    public:
      float x, y;
    
      static Point NewCartesian(float x, float y) {
        return{ x, y };
      }
    };
    
    int main()
    {
      vector<Point> vectorPoint;
      for (int i = 0; i < 10000; i++) {
        Point& p = Point::NewCartesian(5, 10);
        vectorPoint.push_back( p );
        // vectorPoint.push_back( Point::NewCartesian(5, 10) );
    
        Point& p2 = Point::NewPolar(5, M_PI_4);
      }
    
      cout << "deneme" << endl;
    
      getchar();
    
      return 0;
    }
    

Спасибо за помощь,

Приветствия

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

... Я знаю, что он должен храниться в куче.

Во-первых, пожалуйста прочитайте это объяснение того, почему предпочтительнее говорить о автоматических и динамических временах жизни объектов, а не стеке / куче.

Во-вторых, этот объект не размещен ни динамически, ни в куче. Вы можете сказать, потому что динамическое распределение использует выражение new или библиотечную функцию, такую ​​как malloc, calloc или, возможно, mmap. Если у вас нет ни одного из них (и вы почти никогда не должны), это не динамично.

Вы возвращаете что-то по значению, так что время жизни этой вещи определенно автоматическое.

Когда точка создается, когда она уничтожается?

Если вы напишите полный набор конструкторов копирования / перемещения и операторов присваивания, а также деструктор, вы можете просто установить в них точки останова в отладчике и см. , где они вызываются. Или пусть все они напечатают свои указатель this и входные аргументы (т. Е. Исходный объект, который перемещается или копируется).

Однако, поскольку мы знаем, что объект автоматический, ответ прост - когда он выходит из области видимости.

Должен ли я использовать Point & p или Point p для возврата Point :: NewCartesian?

Определенно, второе: первое возвращает ссылку на объект с автоматическим временем жизни в области действия функции NewCartesian, означая, что объект, на который ссылаются, уже мертв к моменту, когда вызывающая сторона получает ссылку.

Наконец, этот код

Point& p = Point::NewCartesian(5, 10);

странно - из-за чтения кода сложно определить время жизни Point, на которое ссылается p. Это может быть некоторый статический / глобальный / другой объект с динамическим временем жизни, для которого NewCartesian возвращает ссылку, или (как на самом деле), вы можете привязывать ссылку к анонимному временному объекту. Нет смысла писать так вместо

Point p = Point::NewCartesian(5, 10);

или просто передавая временную прямую к push_back, как в вашем коде с комментариями.


Кстати, дизайн Point очень странный. Он имеет открытые члены данных, но закрытый конструктор и открытый статический метод, который просто вызывает конструктор. Вы можете полностью опустить конструктор и статический метод и просто использовать агрегатную инициализацию или опустить статический метод и сделать конструктор общедоступным.

0 голосов
/ 03 сентября 2018

1а. Нет, это в стеке, но прочитайте ответ от Бесполезно , почему термины stack и heap не лучший выбор.

1b. Копируется, когда вы звоните push_back.

2. Он уничтожается сразу после создания, потому что он существует только в рамках вызова NewCartesian и в течение всего периода обработки возвращаемого значения.

3a. Вы используете ссылку всякий раз, когда у вас есть действительный экземпляр и хотите передать его функции, не создавая копию. В частности, функция должна иметь опорный параметр.

3b. Вы должны использовать Point p, а не Point& p, потому что прямо сейчас вы получаете висячую ссылку на объект, который больше не существует (см. 2.)

Как отметил Стивен В. Классен в комментариях, ваш лучший вариант - это код, который вы закомментировали: vectorPoint.push_back( Point::NewCartesian(5, 10) );. Передача вызова в NewCartesian непосредственно в push_back без создания отдельной локальной копии, позволяет компилятору оптимизировать его так, чтобы память создавалась именно там, где этого хочет push_back, и избегая любых промежуточных выделений памяти или копий. (Или, технически, он позволяет использовать оператор перемещения.)

...