Я помню, что Скотт Мейерс научил меня этому
func(shared_ptr(new P), shared_ptr(new Q));
опасно, потому что (если я правильно помню) порядок из выделение памяти, подсчет ссылок (строительство) и присвоение параметры функции позволяет утечка (теоретически?) появляться в редких случаях. Чтобы предотвратить это, следует заключить shared_ptr
в вызове функции, например в make_shared()
,
func(make_shared<P>(), make_shared<Q>());
Вот некоторые обсуждение об этом тоже.
Я хотел бы знать, есть ли (текущие) компиляторы в поле, на определенных системах это действительно может оставить какую-то дыру в некоторых случаях ошибки? Или те времена прошли, или они были только теоретическими, так или иначе?
Самое интересное было бы знать, есть ли у кого-то из них эта проблема:
Кто-нибудь наблюдал такое поведение на своей конкретной платформе?
func(shared_ptr(new P), shared_ptr(new Q));
Компилятор C ++ может реализовать это в следующем порядке:
(Компилятор может выполнять 1, 2, 3 и 4 в любом порядке, если 1 перед 4 и 2 перед 3).
В порядке выше, если P
конструктор или вызов new
броски, Q
утечка памяти (память выделяется, но shared_ptr
еще не построен вокруг него).
Как таковой, вы должны позвонить std::make_shared
(который обрабатывает исключения при распределении изящно), и вы знаете, что когда std::make_shared
вернулся за одним из них, shared_ptr
полностью построен и не будет течь.
Я хотел бы знать, есть ли (текущие) компиляторы на местах, в некоторых системах, которые действительно могут оставить некоторую дыру в некоторых случаях ошибки?
Все компиляторы, соответствующие стандартам, будут иметь такое поведение.
Это не проблема платформы, это проблема безопасности исключений. Итак, ответ на ваш актуальный вопрос: все эти платформы могут демонстрировать проблему.
Проблема утечки памяти возникает из-за 2 вещей:
new
может бросить bad_alloc
Документы для boost::shared_ptr
захватить это красиво Вот
Подробно об общей проблеме здесь (GOTW)
Причина, по которой это может быть «редким», возникает потому, что на самом деле это не так часто bad_alloc
, но ваш код должен обрабатывать эту возможность безопасно, чтобы избежать утечек памяти.
(Я говорю «может» показать это — я не проверил, что они все бросают bad_alloc
если new
не может …)
потому что оба new
Сначала будет выполнена операция, а затем они будут переданы в shared_ptr
конструктор, но который shared_ptr
Конструкции first не указаны, поэтому один из вновь созданных объектов может вызвать утечку памяти.
Это небезопасно на любой платформе с оптимизатором переупорядочения, если этот оптимизатор выполняет следующую оптимизацию A;B;A;B => A;A;B;B
, Эта оптимизация повышает эффективность кэширования кода, так что в целом это хорошая идея.
Очевидно, что оптимизатор может переставлять B и A только в том случае, если их относительный порядок не указан, что здесь имеет место.