Перейти к содержимому
шпаргалка.
Esc
навигацияоткрыть⌘Jпредпросмотр
На этой странице

Память и указатели

Все темы C++ Developer

В чем разница между указателем и ссылкой?

Основные различия между указателем и ссылкой в C++:

  1. Синтаксис и использование:

    • Указатель: Переменная, которая хранит адрес другой переменной.

      int a = 10;
      int* ptr = &a;
    • Ссылка: Альтернативное имя для уже существующей переменной.

      int a = 10;
      int& ref = a;
  2. Инициализация:

    • Указатель: Может быть инициализирован позже или изменён для указания на другой адрес.

      int b = 20;
      ptr = &b;  // Теперь ptr указывает на b
    • Ссылка: Должна быть инициализирована сразу при создании и не может быть изменена для ссылок на другой объект.

      int c = 20;
      ref = c;  // Изменяет значение a на 20, но ref по-прежнему ссылается на a
  3. Нулевое значение:

    • Указатель: Может быть нулевым (nullptr), что означает, что он не указывает ни на какой объект.

      int* ptr = nullptr;
    • Ссылку нужно связать с подходящим объектом или функцией. Сам язык не отслеживает время жизни цели: после её уничтожения ссылка может стать висячей.

  4. Операции разыменования:

    • Указатель: Требует операцию разыменования (*) для доступа к значению, на которое указывает.

      int value = *ptr;
    • Ссылка: Не требует специальной операции для доступа к значению.

      int value = ref;

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


Для чего нужен указатель на функцию? Как его объявить?

Указатель на функцию используется для хранения адреса функции и позволяет вызывать функции через этот указатель. Это полезно для реализации обратных вызовов (callbacks), таблиц виртуальных функций и гибких механизмов обработки событий.

Объявление указателя на функцию:

  1. Объявление:

    • Для функции с прототипом void foo(int):

      void (*funcPtr)(int);
  2. Инициализация:

    • Присвоение адреса функции указателю:

      funcPtr = foo;
  3. Использование:

    • Вызов функции через указатель:

      funcPtr(5);  // Вызывает foo(5)

Пример:

#include <iostream>// Обычная функция
void foo(int x) {
    std::cout << "Value: " << x << std::endl;
}

int main() {
    // Объявление указателя на функцию
    void (*funcPtr)(int);

    // Инициализация указателя адресом функции foo
    funcPtr = foo;

    // Вызов функции через указатель
    funcPtr(5);

    return 0;
}

Что будет, если забыть вызвать delete? Когда освободится та память?

Если забыть вызвать delete для динамически выделенной памяти, произойдёт утечка памяти (memory leak). В таком случае:

  • Память, выделенная с помощью new, не будет освобождена.

  • Память будет занята до завершения программы.

  • Постепенно такие утечки могут привести к исчерпанию доступной памяти, что может вызвать замедление или крах программы.

Память, не освобождённая через delete, будет освобождена операционной системой при завершении программы, но в процессе выполнения программы эта память останется недоступной для повторного использования.


Что такое умный указатель? Какие умные указатели есть в стандартной библиотеке?

Умный указатель хранит указатель и реализует правила владения. unique_ptr освобождает ресурс при уничтожении или reset, shared_ptr при исчезновении последнего владельца. weak_ptr не владеет объектом и сам его не освобождает.

  1. std::unique_ptr: Эксклюзивное владение ресурсом. Не может быть скопирован, только перемещён.

  2. std::shared_ptr: Совместное владение ресурсом. Поддерживает подсчёт ссылок, освобождает память, когда последний shared_ptr выходит из области видимости.

  3. std::weak_ptr: Неблокирующая ссылка на ресурс, управляемый std::shared_ptr. Не увеличивает подсчёт ссылок.

Пример:

#include <memory>

std::unique_ptr<int> ptr1(new int(10));
std::shared_ptr<int> ptr2 = std::make_shared<int>(20);
std::weak_ptr<int> ptr3 = ptr2;

Как работает const для переменных, ссылок и указателей и от чего зависит размер указателя?

Константность переменной, ссылки, указателя:
  • Константная переменная: Значение не может быть изменено после инициализации.

    const int a = 10;
  • Константная ссылка: Ссылка на константу, через которую нельзя изменить значение.

    const int& ref = a;
  • Константный указатель: Указатель, адрес которого нельзя изменить после инициализации.

    int value = 10;
    int* const ptr = &value;
  • Указатель на константу: Указатель на значение, которое нельзя изменить через этот указатель.

    const int* ptr = &a;
Константный указатель и указатель на константу:
  • Константный указатель ( int* const ): Указатель не может указывать на другой адрес, но данные по этому адресу могут изменяться.

    int value = 10;
    int* const ptr = &value;
  • Указатель на константу ( const int* ): Указатель может менять адрес, но данные по адресу менять нельзя.

    const int* ptr = &a;
Размер указателя:
  • Размер указателя определяется типом указателя и реализацией; проверяйте sizeof. Следующие размеры типичны для распространённых ABI, но не гарантированы стандартом для всех платформ и указателей на члены.
    • 32-битная система: Указатель занимает 4 байта.

    • 64-битная система: Указатель занимает 8 байт.


Что случится, если вернуть ссылку на временный объект?

Если вернуть ссылку на временный объект, то после завершения функции объект будет уничтожен, и ссылка станет “висячей” (dangling reference). Использование такой ссылки приведёт к неопределённому поведению, что может вызвать ошибки или сбои программы.

Эта страница была полезной?