Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Weak_ptr? Они что, шутят? С третьей, или какой там по счету, попытки сделать в STL автоматическое управление памятью, предлагается weak_ptr? Годика через три вопрос «приведите пример, когда нужен weak_ptr» будет встречаться на собеседованиях с такой же частотой, как и вопрос про виртуальное базовое наследование. И с такой же частотой употребляться на практике. Потому что это еще один, тысячный способ гарантированно прострелить себе ногу. А без weak_ptr не будет нормально работать shared_ptr. Ну и зачем тогда всё это?
Будете использовать weak_ptr — получите тухлые указатели. Будете использовать shared — получите out_of_memory.Использование только сильных/слабых ссылок вместо использования голых указателей дает возможность уйти от мыслей о работе с памятью к мыслям о органицации графа зависимостей.
когда уже совершенно точно можно объявлять объекты подлежащими удалениюМы отказываемся от владения вершиной дерева. Если никто не завладел вершиной дополнительно, то дерево будет удалено, кроме поддерева, которым совладеет другой поток. Это поддерево останется валидным, все объекты живы пока им владеет другая сущность. Теперь поток что-то сделал, как-то преобразовал это поддерево и решил оповестить о этом «надкорень» этого дерева. он попытается получить сильную ссылку из слабой и узнает, что объекта уже нет. Все. Он может остановится и не делать ничего. Поток не упадет только лишь потому, что кто-то где-то решил, что час Ч настал и можно удалять всё дерево.
Widget* p = new Widget;
shared_ptr<Widget> a( p );
shared_ptr<Widget> b( p );
Widget* p = new Widget;
intrusive_ptr<Widget> a( p );
intrusive_ptr<Widget> b( p );
intrusive_ptr<Widget>( this );
func(arg1, arg2)
mov arg1, r5 // arg1 mov r1, [addr] // arg2 mov arg2, [r1] // arg2 call func
mov r1, [addr] // arg2 mov arg1, r5 // arg1 mov arg2, [r1] // arg2 call func
// Обратите внимание на следующую строчку
connectionToRelease.reset();
class BadWidget3: public boost::enable_shared_from_this<BadWidget1> {
public:
BadWidget3() {
}
shared_ptr<BadWidget3> f() {
return shared_from_this();
}
};
main()
{
BadWidget3* w = new BadWidget3;
shared_ptr<BadWidget3> w1 = w->f();
}
Безымянные указатели
Проблема использования в разных потоках
template<class T> void atomic_store( shared_ptr<T> * p, shared_ptr<T> r )
{
boost::detail::spinlock_pool<2>::scoped_lock lock( p );
p->swap( r );
}
<...> and the behavior is undefined if the value supplied tooperator delete[](void*)in the standard library is not one of the values returned by a previous invocation of eitheroperator new[](std::size_t)oroperator new[](std::size_t, const std::nothrow_t&)in the standard library.
Ясно. Я ошибся, сказав «без пользовательских библиотек, входящих в стандарт» ибо оператор new имеет свою имплементацию в стандартной библиотеке(обычно обертка над malloc с вызовами конструкторов и бросанием исключений). — в принципе ничем не отличается от, скажем, vector. Правда есть еще ключевое слово new — не помню чем отличается(по моему как раз и вызывает конструктор).Это ключевое слово как раз и вызывает operator new, который должен выделить память под объект, а потом вызывает необходимый конструктор.
А такой вопрос: а почему в стандарте по C++ описано, как должны себя вести пользовательские компоненты, стандартная library? ведь пользовательские компоненты — это не сам язык C++. Пользовательские компоненты написаны на C++ и они конечно имеют свой стандарт поведения — но не являются самим языком. По идее должно быть два источника инфы: pure C++ и C++ standart library, stl, partialy boost(что из буста перешло в C++11), etcНу, библиотека потому и стандартная, потому что входит в стандарт. Это обязательная библиотека, которая должна быть в любой реализации. Хоть разделение на ядро и библиотеку в общем-то здравое, но я не знаю таких языков, где стандартная библиотека разрабатывается совершенно отдельно от ядра языка.
Пять подводных камней при использовании shared_ptr