Прошлые домены не функционирует! Используйте адрес
ARHIVACH.VC.
24 декабря 2023 г. Архивач восстановлен после серьёзной аварии. К сожалению, значительная часть сохранённых изображений и видео была потеряна.
Подробности случившегося. Мы призываем всех неравнодушных
помочь нам с восстановлением утраченного контента!
Откровенно говоря, то, что кажется революционном, — всего лишь последний шаг длинной эволюции.
Эволюция указателей в C++
Указатели существуют в C++ с самого начала. Мы получили их из C. С самого начала развития C++ всегда была тенденция сделать управление указателями более безопасным без значительных потерь.
В C++98 мы получили std::auto_ptr для выражения исключительного владения. Но std::auto_ptr имел большой изъян. Когда вы копирует std::auto_ptr, владение ресурсом передавалось копии. Копирование выглядело как перемещение. Изображение ниже показывает неприятное поведение std::auto_ptr.
Это было очень плохо, приводило к множеству серьёзных багов. Поэтому мы получили std::unique_ptr в C++11, и объявили std::auto_ptr устаревшим в C++11, и окончательно удалили из C++17. Дополнительно мы получили std::shared_ptr и std::weak_ptr в C++11 для управления владением. Вы не можете копировать, но можете перемещать std::unique_ptr, и если копируете или присваиваете std::shared_ptr, счётчик ссылающихся указателей увеличивается. Посмотрите сюда:
Начиная с C++11 C++ имеет многопоточную библиотеку. Это делает управление std::shared_ptr достаточно сложным, потому что std::shared_ptr по определению разделяемое, но не потоко-безопасное. Только контрольная часть со счётчиками является потоко-безопасной, но не доступ к адресу контролируемого ресурса. Это значит, что изменение счётчика — атомарная операция, но вы не имеете гарантии, что ресурс будет удалён ровно один раз. По этой причине мы получаем в C++20 атомарные умные указатели: std::atomic_shared_ptr и std::atmic_weak_ptr. Про детали предложений комитета стандартизации читайте здесь: Атомарные умные указатели.
Теперь переходим к более интересным частям будущих стандартов C++20 и C++23. Указатели будет объявлены устаревшими в C++20 и удалены из C++23. Скажем три слова: Нет Новому New (NNN).
std::unique_ptr спасёт нас
Но подождите, как же догма C++: Не платить за то, что вам не нужно. Как мы сможем программировать без указателей? Просто используйте std::unique_ptr. Из своего дизайна std::unique_ptr такой же быстрый и экономный, как и обычный указатель, и имеет явное преимущество — автоматическое управление ресурсом.
Ниже простой тест производительности.
// all.cpp
#include <chrono>
#include <iostream>
static const long long numInt= 100000000;
int main(){
auto start = std::chrono::system_clock::now();
for ( long long i=0 ; i < numInt; ++i){
int* tmp(new int(i));
delete tmp;
// std::shared_ptr<int> tmp(new int(i));
// std::shared_ptr<int> tmp(std::make_shared<int>(i));
// std::unique_ptr<int> tmp(new int(i));
// std::unique_ptr<int> tmp(std::make_unique<int>(i));
}
std::chrono::duration<double> dur= std::chrono::system_clock::now() - start;
std::cout << "time native: " << dur.count() << " seconds" << std::endl;
}
Эта программа выделяет и освобождает память для 100 миллионов int. Я использую указатели, std::shared_ptr и std::unique_ptr в двух вариациях. Я компилирую программу с и без максимальной оптимизации в Linux и в Windows. Получаются такие числа:
Две вариации std::unique_ptr на Linux и Windows показывают такую же производительность, как обычные указатели. За деталями этого теста обратитесь к моей прошлой статье: Потребление памяти и производительность умных указателей.
Семантика владения
Честно говоря, мы используем указатели и, в частности, обычные указатели очень часто. Вопрос, должны ли вы использовать указатель, сводится к следующему: Кто владелец? К счастью, с помощью кода мы можем чётко выразить это.
Локальные объекты. Рантайм C++ как владелец автоматически управляет жизнью таких ресурсов. То же самое относится к глобальным объектам или членам класса. Справочники сводят это к области видимости.
Ссылки: я не владелец. Я только обеспечиваю, что ресурс не может быть пустым.
Обычные указатели: я не владелец. Я только ссылаюсь на ресурс, если он есть. Я не должен удалять ресурс.
std::unique_ptr: я исключительный владелец ресурса. Я могу явно освободить мой ресурс.
std::shared_ptr: я разделяю ресурс с другими std::shared_ptr. Я могу явно удалить мой разделяемый ресурс, если он больше никому не нужен.
std::weak_ptr: я не владелец ресурса, но я могу временно разделять ресурс при вызове моего метода std::weak_ptr::lock.
Нам нужно будет изменить только одну из шести практик использования указателей и мы рады следующему шагу в развитии C++.