All streams
Search
Write a publication
Pull to refresh
12
0
Send message
Давайте-же смотреть на проблему в целом.

Давайте, представим для простоты, что граф наших объектов — это дерево, с жесткими ссылками (и, слабыми/weak обратными ссылками). Варианты, когда листья дерева могут ссылаться на другие листья пока не рассматриваем.
shared(strong) ссылки реализуют семантику владения без необходимости вызова деструктора самостоятельно.

Основная проблема с голыми указателями — это определить эту самую семантику владения — кто должен вызывать delete/delete[]? shared_ptr/weak_ptr как раз указывают явно эту семантику в коде.

Вернемся к нашему примеру. У нас есть «дерево» объектов. Мы решаем, что нам нужно сделать что-то в другом потоке в каким-то поддеревом. Мы передаем в другой поток это поддерево, скопировав shared_ptr. Тем самым мы разделили владение этим поддеревом с другой сущностью (потоком). Теперь, предположим наступает тот самый момент,
когда уже совершенно точно можно объявлять объекты подлежащими удалению
Мы отказываемся от владения вершиной дерева. Если никто не завладел вершиной дополнительно, то дерево будет удалено, кроме поддерева, которым совладеет другой поток. Это поддерево останется валидным, все объекты живы пока им владеет другая сущность. Теперь поток что-то сделал, как-то преобразовал это поддерево и решил оповестить о этом «надкорень» этого дерева. он попытается получить сильную ссылку из слабой и узнает, что объекта уже нет. Все. Он может остановится и не делать ничего. Поток не упадет только лишь потому, что кто-то где-то решил, что час Ч настал и можно удалять всё дерево.

Заметтьте, в описаном примере никто не вызывает деструктор. Это не нужно. Нужно всего лишь отказаться от владения. Программируя я не хочу думать когда и кто должен будет вызывать конструкторы/деструкторы (в идеале). Я хочу описывать задачу на более высоком уровне. Я хочу сказать «на момент вызова этого метода» (или «пока жив этот объект») такие-то данные должны оставаться валидными. И это все. Когда мне данные перестают быть нужны я хочу просто отказаться от владения ими. Эту семантику владения и описывают strong/weak умные указатели.

Описанный вами пулл — это лишь одно из возможных решений. И не всегда выгодное. Например, если данные, с которыми мы работаем иммутабельны, то shared_ptr будет сильно выигрывать по памяти, поскольку не потребуется их копировать в каждый из N пуллов, будут созданы только N shared_ptr, указывающие на одну область памяти.
Obj-C используется как раз в гуёвых приложениях, и проблем в графом объектов (именно, тех, которые описали вы) не наблюдается.
Будете использовать weak_ptr — получите тухлые указатели. Будете использовать shared — получите out_of_memory.
Использование только сильных/слабых ссылок вместо использования голых указателей дает возможность уйти от мыслей о работе с памятью к мыслям о органицации графа зависимостей.
Предположим, что объект A имеет слабую ссылку на B. В методе A из слабой ссылки (weak_ptr) создается сильная ссылка(shared_ptr), и внутри скоупа этого метода идет работа с сильной ссылкой — она точно не протухнет, пока shared_ptr жив. Эту ссылку можно передавать в другие методы, даже асинхронные, и объект A будет жить пока это необходимо этому асинхронному методу (например).
Системе подчета ссылок не одно десятилетие (Cocoa/Objective-C, Delphy), и у нее есть свои недостатки, но я очень рад, что она наконец-то появилась и в C++11.
Посмотрите на Objective-C — язык полностью построенный на модели подсчета ссылок. И нет никаких проблем (на самом деле есть, но не те, что описаны вами) с многопоточностью. И там weak ссылки работают отлично, во многих местах. Там все просто — создаете strong ссылку из weak для скоупа, в котором работаете. Дя этого shared_ptr / weak_ptr и разрабатывались.
«Перекрестные ссылки» и «кольцевые ссылки» имеют вполне устоявшийся в русском языке термин «Циклические ссылки» (от англ. retain cycle).
Описанный в статье простой и очевидный вид циклических ссылок. Гораздо более часто встречающийся в реальных приложениях, и гораздо более трудно находимые — это когда объект A имеет жесткую ссылку на B, который имеет жесткую ссылку на С, который имеет жесткую ссылку на A.
А как насчет поддержки Xib/Storyboard из UIKit? У меня есть простенькая игрушка, но Cocos2d там используется в паре с CCViewController только на одном экране. Все остальное — менюшки всякие и т.п. — на Storyboard. Спортирует оно его?
Вы бы лучше эти аббревиатуры расшифровали. В тексте они встречаются один раз. Можете в скобочках оставить для тех, кто в курсе. Но три аббревиатуры в одном (первом-же) предложении — перебор )
Во во. Только прочитав в середине статье про ГК РФ догадался о какой стране идет речь.
MNP, ЕГАИС, КЦНДСИ, API. ГК РФ. Единственное знакомое сочетание — API. Остальное большинства населения означает не больше чем ФГБНУ НИИ РИНКЦЭ (ИМХО)
Ну да. Но на то он и велосипед, чтобы попытаться самому реализовать уже реализованное.
Если вы пишете только под iOS/OSX и используете, clang с эпловой стандартной библиотекой с++11, то вы можете и лямбды и блоки хранить в NS-контейнерах:
NSArray* array = @[ []{ std::cout << "hello" << std::endl; } ];
void(^say_hello)() = [array lastObject];
say_hello();
А теперь представьте, что вы пишете кроссплатформенный код на чистом С++. Например вы используете cocos2d-x, и хотите чтобы ваш код запускался на iOS, Android, WindowsPhone8, BlackBerry, MeeGo, win32, Linux, Win8 Metro, Mac OS X. Вы там не сможете использовать Objective-C блоки в принципе. Вот тут и появляются велосипеды ))
Простите, был взволнован.
>clang++ --version
Apple LLVM version 5.0 (clang-500.1.61) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.4.0
Thread model: posix
Возможно не совсем хороший пример. Мы можем написать как угодно. Разные очереди полезны для абстрагирования от подсистем. Например отделить UI в Main Tread от сетевой подсистемы. Сетевую подсистему от системы записи/чтения с диска, и все предыдущие системы от подсистемы обработки изображений (к примеру).
Ну, если говорить о Grand Central Dispatch, то он имеет C интерфейс, и оперирует блоками, аналогами которых есть лямбды в C++. Практически ничего от obj-c (кроме блоков) в GCD нет.
Сравните
obj-c:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // do smth
    dispatch_async(dispatch_get_main_queue(), ^{
        // do smth in main thread
    });
});

C++:
dispatch::queue(dispatch::QUEUE_PRIORITY::DEFAULT).async([]{
    // do smth
    dispatch::queue::main_queue()->async([]{
        // do smth in mai thread
    });
});


Для вас замена "[]" на "^" при объявлении замыкания настолько критична?
Хорошо. Представьте, что вам нужно вычитать N файлов и распарсить их. В другом участке кода вам нужно послать запрос по сети (пусть синхронно, не суть), а еще вам нужно сгенерировать M изображений в фоне (или вычитать их из сети), а потом изобразить их в главном потоке. Потом… тут подставьте еще много полезных, нужных вещей, которые так нужны современным приложениям.
Вы можете создать по потоку для каждого типа операций. И устроить очередь в этом отдельном потоке. При уничтожении этой очереди удаляем поток.
Но создание/удаление потока довольно дорогостоящая операция. Проще держать уже готовый поток, который будет обрабатывать задания из многих очередей. В этом и есть смысл пула потоков. У нас может быть одновременно очень много очередей, Добавление/удаление очередей и добавление заданий в очередь очень дешевая операция. Задания выполняются согласно приоритетам.
Можете воспринимать очереди как очень легковесные потоки
Зачем нам надо много пулов потоков я пока так и не понял
У нас только один пулл потоков. Он синглтон
А в чём именно удобство? Мне это совершенно не очевидно
SRP — жеж. Ну и отсутствие возможности для dead-lock'а — если вся работа с одним ресурсом (файловой системой, к примеру) идет через одну очередь.
Нуу например std::async в реализации MS именно так и работает.
std::async — это тот еще костыль ИМХО. Получение значения оттуда через std::future полностью блокирует текущий поток (что для Main Thread не приемлемо в принципе). А я не хочу блокироваться, я хочу получить уведомление о том, что все закончилось в контексте текущей очереди тогда, когда данные будут получены.
по вашему -Werror не пресечет на этапе компиляции?
Основная проблема таких статей: их никто не читает до конца. Вот и я не осилил.
4 (четыре) списка, в каждом из которых больше 3 пунктов, и объем текста больше чем в «основной» статье — это как-то чересчур и вызывает отторжение.
Первая картинка по запросу в гугл. И алюминиевый сгодится

Information

Rating
Does not participate
Registered
Activity