Прежде всего, стек, куча и статическая область хранения — это все открытые в памяти пространства. В частности, в C++, если вы создаете объект без использования new, то пространство для этого объекта открывается в стеке, например Нам не нужно беспокоиться о месте, программа автоматически освободит его после использования, и вам не нужно беспокоиться об утечках памяти.
Пространство, подобное этому типу пространства, является статическим пространством. В таком пространстве не нужно беспокоиться об утечках памяти. Статическое пространство — это пространство, которое открывается перед запуском программы.
Вот два способа использования статики:
Первый — статические переменные,
статический int a =10 ;
Фактически такую переменную a можно использовать как глобальную переменную.
Второй тип — локальные статические переменные.
void a(int b){
статический int c = 10;
с+=1;
}
По сравнению с обычными локальными переменными, такие локальные статические переменные имеют более длительный жизненный цикл и не будут повторно инициализироваться при каждом вызове функции его значение будет обновлено в открывшемся пространстве.
Во-вторых, static также может изменять функции-члены, например
cpp
class Math {
public:
static int add(int a, int b) { // 静态函数
return a + b;
}
};
int main() {
int sum = Math::add(1, 2); // 直接调用
}
Характеристики такой статической функции-члена очевидны с первого взгляда: ее можно вызывать без создания объекта.
Конечно, существуют также статические переменные-члены, особенностью которых является то, что все объекты класса могут вносить свой вклад в эту статическую переменную-член. (На самом деле, статические методы-члены похожи).
Насколько я понимаю, для всех статически измененных функций или переменных они уже открыли пространство до запуска программы. Это пространство не зависит от каких-либо других факторов. Они не будут инициализироваться снова ни в какой ситуации и будут обновлены. и навсегда сохранил собственную ценность. На это не будут влиять другие факторы, и каждый может легко назвать это пространство или значение.Здесь есть несколько похожих глобальных переменных.
Затем давайте снова поговорим о куче. Куча похожа на стек. Как я только что сказал, стек — это пространство, открываемое без использования new при создании объекта, а куча — это пространство, открываемое с помощью нового ключевого слова, когда Создание объекта. Он создается с использованием нового символа в C++. Пространство открывается в куче. Этот вид пространства не управляется программой и контролируется программистом вручную. Поэтому пространство, открываемое новым, также является ситуация, когда легко возникают утечки памяти, поэтому этот способ освобождения места требует от нас ручного удаления. Есть два способа удаления:
cpp
Person::~Person() {
delete this; // 手动释放内存
}
cpp
Person* p = new Person();
// ...
delete p; // 主动调用delete释放内存
Вышеупомянутый использует деструктор для освобождения памяти, а приведенный ниже использует деструктор для ручного удаления памяти.
На самом деле тут возникает вопрос: не генерирует ли C++ автоматически деструктор по умолчанию при создании класса, тогда зачем мне вручную писать деструктор для освобождения памяти? ?
Фактически принцип, упомянутый выше, остался прежним. В частности, мы используем ключевое слово new, чтобы освободить место в куче . Это пространство состоит из двух частей. Одна часть - это наш объект. Другая часть занимаемого пространства - это пространство, занятое некоторыми нестатическими переменными-членами.Системный деструктор по умолчанию автоматически освобождает эти нестатические переменные-члены, оставляя эту часть объекта. Занятое пространство необходимо освободить вручную, поэтому нам нужно вручную написать деструктор. (Подумайте об этом внимательно: если пространство кучи также может быть освобождено системным деструктором по умолчанию, то мы можем даже не увидеть деструктор.)
Далее давайте поговорим о поверхностном и глубоком копировании.
Мелкое копирование и глубокое копирование происходят в конструкторе копирования.Давайте кратко поговорим о конструкторе копирования.Я понимаю, что для копирования адреса объекта в новый объект используется символ адреса.
Конкретный код:
класс Фу {
интервал м_р;
публика:
Фу() {
m_p = новый int (10);
}
Foo(const Foo& другое) {
m_p = другое.m_p;
<а я=0>
};
Красная часть — это конструктор копирования. При передаче переменных вы можете копировать и передавать значения в обычном режиме. Однако, если это указатель, вместо значения передается указатель.
код показан ниже:
cpp
class Foo {
int* m_p;
public:
Foo() {
m_p = new int(10);
}
Foo(const Foo& other) {
m_p = other.m_p; // 拷贝指针,共享同一块内存
}
};
int main() {
Foo f1;
Foo f2 = f1; // 调用浅拷贝的拷贝构造函数
delete f1.m_p; // f1释放内存
// f2.m_p指向已释放的内存,产生undefined behavior
}
После тщательного анализа мы видим, что созданный нами объект f1 автоматически вызывал конструктор при его создании, чтобы освободить 10 мест в куче для указателя m_p, а затем мы создали второй объект f2, так что f2=f1, то есть вызов нашего конструктора копирования, затем посмотрим, записано ли это в конструкторе копирования: m_p=other.m_p;Это предложение означает изменение m_p f1< a i=1>address< /span> передается в m_p из f2, верно? Это означает, что адрес переменной-члена m_p объекта f1 и адрес переменной-члена m_p объекта f2 теперь являются одним и тем же адресом. Это поверхностная копия, какие проблемы могут возникнуть? Первый известный нам способ - вручную освободить память кучи. Как видно из приведенного выше кода, мы используем delete, чтобы освободить память кучи f1, но переменная m_p f2 также указывает на этот адрес, и он освобождается. для него. К кому относится f2? Таким образом, это приведет к ситуации, называемой висячим указателем (называемой по-другому...). Эта программа сообщит об ошибке.
Во-вторых, мы забываем удалить открытое пространство кучи, что напрямую приведет к утечке памяти.
Так как же это решить?
Поскольку речь идет о совместном использовании кучи, мы можем открыть новое пространство кучи для f2.
Да, этот метод является глубоким копированием.
Конкретный код:
cpp
class Foo {
int* m_p;
public:
Foo() {
m_p = new int(10);
}
Foo(const Foo& other) {
// m_p = other.m_p; // 拷贝指针,共享同一块内存
m_p = new int(*other.m_p);
}
};
~Foo(){
delete m_p;
}
int main() {
Foo f1;
Foo f2 = f1; // 调用浅拷贝的拷贝构造函数
delete f1.m_p; // f1释放内存
// f2.m_p指向已释放的内存,产生undefined behavior
}
Легко понять, что мы открыли новое пространство в куче для вновь скопированного объекта, избежав тем самым только что возникшей проблемы.
Вот и все в двух словах. . Буду продолжать обновлять ~