Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / С++ где взять shared_ptr когда он так нужен? [РЕШЕНО] (3 стр)

С++ где взять shared_ptr когда он так нужен? [РЕШЕНО] (3 стр)

Страницы: 1 2 3 4 5 6 Следующая »
DelfigamerПостоялецwww6 июля 201818:05#30
=A=L=X=
Ага, расскажи мне про интрузивные указатели. :3

*Lain*
> и вик_птр.лоск поддерживает)
И это тоже интрузивными решается - подобно шареду, храним strong_refcount и total_refcount; по истечении strong_refcount вызываем деструктор, по истечении total_refcount освобождаем память.

grishman
> It is permitted to call shared_from_this only on a previously shared object,
> i.e. on an object managed by std::shared_ptr<T>. Otherwise the behavior is
> undefined
Это не является особенностью enable_shared_from_this; это свойство присуще всем умным указателям - нельзя вызывать delete на указателе, полученном от стековой переменной.
В C++ предполагается, что программист знает, что делает, и поэтому в общем случае не тратит время на проверку правильности во время выполнения - у нас всего 16мс на кадр, поэтому нам непозволительно тратить время на то, чего можно избежать.

grishman
> Оборудование и С++ никак не связаны, это заблуждение.
Глупенький, я говорил о написании ядра ОС, драйверов и ПО микроконтроллеров.

grishman
> аллокация памяти в C# работает быстрее
А вот это утверждение является фактически неверным.

grishman
> Вообще-то смысл RAII в другом:
Вообще-то это оно и есть, только вместо "автоматизируется" они решили сказать "неразрывно совмещается".

grishman
> Надо отметить что С++ с этой задачей справляется хреново, по следующим причинам:
Это не причины, а примеры неправильного применения средств C++.

grishman
> В целом RAII не позволяет инициализировать и деинициализировать объект несколько раз в ходе его жизненного цикла.
Так и задумано. Инициализация и деинициализация, по определению - это и есть начало и конец жизни объекта. Задача конструктора - создать объект из мрака энтропии, а задача деструктора - окончить его существование и вернуть объект в бездну. Нельзя повторно инициализировать то, чего уже не существует.
Зато можно придержать память, где находился объект, и вместо того, чтобы возвращать память аллокатору и тут же по-новой забирать - можно вызвать деструктор старого объекта и затем создать новый на том же участке памяти. Можно взять память сразу для десяти объектов, по очереди инициализировать пять и оставить ещё пять слотов на потом.

grishman
> В любой момент можно сломать конструкцию на любом уровне абстракции, и
> компилятор даже слова не скажет.
Это если неправильно им пользоваться.
При правильном использовании, все опасные места сосредотачиваются в небольших, легко отлаживаемых участках.

grishman
> за это время мог в любой момент прострелить себе ногу
Я всегда читаю документацию перед использованием инстумента. Если бы я пользовался std::shared_ptr - я бы об этом знал и учитывал.

grishman
> Какая выразительность, если мне нужно наследоваться вот от этого
> std::enable_shared_from_this<T>, и при этом помнить что объект нужно создать в
> куче и обернуть в shared_ptr чтобы всё это работало?
Это - следствие контроля, который предоставляет C++. Как я уже говорил - язык не делает ничего, о чём его не просят. Выразительность заключается в том числе и в том, что о всех предпринятых действиях сообщается явно в коде.
Например - если в объекте откладываются дополнительные 8 байт, чтобы хранить умный указатель на себя, это явно указывается в коде наличием std::enable_shared_from_this.

grishman
> На каждую функцию в STL по целому абзацу противопоказаний "что с ней нельзя
> делать чтобы не убиться".
Как я уже много раз говорил - C++ делает только то, о чём его попросят. Если проверка правильности требует дополнительных действий, которые замедляют программу или занимают память - плюсы не будут её делать без явного на то указания.
Между прочим, достаточно широкий спектр ошибок ловится в обычном режиме отладки, в том числе и порча стека, и shared_from_this() в конструкторе.

grishman
> С++ появился в 1983, C# - в 2001. Выходит чтобы следовать твоим рекомендациям,
> программистам С++ следовало повременить с программированием и подождать лет так
> 18. На самом деле всё проще, С++ - это Си-подобный язык, который придуман
> Си-программистами.
Да не, в те времена изначальные требования к квалификации программистов были выше, так что к появлению крестов опытных программистов было вполне достаточно, чтобы начать применять язык по назначению.

DelfigamerПостоялецwww6 июля 201818:08#31
ardru
> Хорошо. Как вам поможет умный указатель, когда, например, std::vector
> переполнился и переехал на новое место?
А нахрена тыкать умными указателями на автоматические объекты?

А какие вообще объекты могут осмысленно использоваться и через указатели, и через переменные?

Eugene
> Я заметил любопытную корелляцию.
> Чем меньше разработчик пишет код жопой, тем меньше у него сегфолтов.
> Я точно помню, как в 18 лет мог ковыряться целую неделю с сегфолтом.
> Сейчас же я не могу вспомнить, когда последний раз у меня было что-то
> подобное.
>
> Теперь я просто пишу код так, чтобы в нем не могло быть сегфолтов.
> Контейнеры и умные указатели — хороший инструмент для такой задачи.
Ну я же и говорю - если использовать кресты правильно, то всё будет и быстро, и надёжно.

Правка: 6 июля 2018 18:10

ardruПостоялецwww6 июля 201818:34#32
Delfigamer
> аллокация памяти в C# работает быстрее, и такой эффективный сборщик мусора на
> С++ всё равно технически не навелосипедить.
На C++ можно "навелосипедить" любой сборщик мусора, вместе с виртуальной машиной С# и её сборщиком мусора.

Правка: 6 июля 2018 18:34

ardruПостоялецwww6 июля 201818:41#33
Delfigamer
> А какие вообще объекты могут осмысленно использоваться и через указатели, и
> через переменные?
да любые, всё зависит от контекста!
KartonagnickЗабаненwww6 июля 201818:51#34
Delfigamer
> Это не является особенностью enable_shared_from_this; это свойство присуще всем
> умным указателям - нельзя вызывать delete на указателе, полученном от стековой
> переменной.


ничто не мешает наследовать класс от enable_shared_from_this,
а потом создавать объект на стеке.

http://rextester.com/HUG11193

//================================================================================
//================================================================================
#include <cassert>
#include <cstddef>
#include <atomic>


template<class T> class copies
{
    typedef std::atomic<size_t>
        count_t;
public:
    ~copies()
        {
            assert(instances() > 0 &&
                "ERROR: DESTRUCTOR CALLED WITHOUT CONSTRUCTOR" );
            --instances__();
        }

    copies() noexcept { ++instances__(); }

    copies(const copies&)noexcept { ++instances__(); }
    copies(copies&&)     noexcept { ++instances__(); }

    static size_t instances() noexcept { return instances__(); }
private:
    static count_t& instances__() noexcept
        { static count_t n(0); return n; }
};

//================================================================================
//================================================================================
 
#include <iostream>
#include <memory>

// --- пример иллюстрация, как можно возвращать валидный
// this->shared_from_this()
// для объекта созданного на стеке
struct sample: std::enable_shared_from_this<sample>, copies<sample>
{
    typedef std::enable_shared_from_this<sample>
        enable_shared;
    
    typedef std::shared_ptr<sample>
        psample;

    static sample create() { return sample(); }    
    size_t id() { return reinterpret_cast<size_t>(this); }

    sample()
        :mThis(this, [](sample*){})
    { std::cout <<"["<< id() <<"]ctor\n"; }

   ~sample()
    { std::cout <<"["<< id() <<"]dtor: " << instances() <<'\n'; }

    sample(const sample& r)
        :enable_shared(r)
        ,copies<sample>()
        ,mThis(this, [](sample*){})
    { std::cout <<"["<< id() <<"]copy: " << instances() <<'\n'; }

    sample(sample&&)
        :mThis(this, [](sample*){})
    { std::cout <<"["<< id() <<"]move\n"; }

    psample shared() { return this->shared_from_this(); }
    

    psample mThis;
};


int main()
{
    // --- пример иллюстрация, как можно возвращать валидный
    // this->shared_from_this()
    // для объекта созданного на стеке

        {
        auto l1 = sample::create();
        std::cout<<"users: " << l1.instances()<<'\n';
        assert(sample::instances() == 1);

        auto s = l1.shared();
        assert(sample::instances() == 1);

        auto t = l1.shared_from_this();
        assert(sample::instances() == 1);

        auto l2 = l1;
        assert(sample::instances() == 2);
    }
    assert(sample::instances() == 0);

}


такое бывает полезным,
когда хочется юзеру дать в руки обычный автоматический объект,
упрятав под капот всю его смартовскую природу.

что бы юзеру не приходилось вникать в детали реализации компонента,
только для того, что бы его использовать.

и не подносить ему всякий говнокод, прикрываясь гордыми словами:
> Delfigamer
> В C++ предполагается, что программист знает, что делает,

Правка: 6 июля 2018 18:56

KartonagnickЗабаненwww6 июля 201819:04#35
grishman
> 1) Отсутствие поддержки виртуальных функций внутри конструкторов.
во-первых, полиморфизм не перестает работать на момент работы конструктора.
во-вторых, если вы сейчас за пыхопэшный бред - тогда потрудитесь растолковать: где здравый смысл?

grishman
> и при этом помнить что объект нужно создать в куче и обернуть в shared_ptr
> чтобы всё это работало?

у вас проблема написать инвариантный класс?
заставлять юзера помнить и учитывать нюансы что бы просто использовать - говнокод, и признак дилетанта.

Правка: 6 июля 2018 19:29

KartonagnickЗабаненwww6 июля 201819:06#36
ardru
> Современный Си++ можно сравнить с большим рестораном, где меню состоит из 25
> увесистых томов на китайском, причём многие блюда

кресты - простой язык.
не сложнее, чем жава, или сишарп.
какие 25 томов?

ardruПостоялецwww6 июля 201819:24#37
Kartonagnick
> кресты - простой язык.
Браво, маэстро!
EugeneУчастникwww6 июля 201819:53#38
ardru
> Как вам поможет умный указатель, когда, например, std::vector переполнился и
> переехал на новое место?
Тут есть два варианта.
Либо у меня вектор указателей, и все указатели при переезде остаются нетронутыми.
Либо у меня вектор значений, и я физически не могу получить умные указатели на элементы этого вектора.
Ещё как вариант, если у меня интрузивные указатели, то я не смогу хранить такие объекты в векторе по значению. Ибо они non-copyable и non-movable.
grishmanПользовательwww6 июля 201820:54#39
*Lain*
Boost слишком жирный чтобы цеплять его ради пары-тройки классов. Собственно это одна из причин почему раньше (до С++11)  я не использовал function и shared_ptr, предпочитая собственные велосипеды. Но раз уж они вошли в стандарт, то можно и переучиться.

Suslik
> умных указателей на себя вообще нет. ребёнок не может существовать без
> родителя, потому что при удалении родителя удаляются все дети.
Это хорошее решение, так устроены виджеты в том же Qt. Но я не могу сделать архитектуру как захочется, т.к. этот код пишется в рамках тестового задания, и далеко от заказанного в нём API, выйти нельзя. При этом в качестве инструментов нужно использовать только STL и Boost, поэтому свои велосипеды тоже отсекаются.

Wraith
> А как ты хотел?
Раньше я бы применил собственные интрузивные контейнеры, унаследовал бы Widget от класса Node, и забыл бы. При этом была бы возможность в любой момент выпилить виджет из памяти через обычный оператор delete, с последующим автовыпиливанием объекта из всех умных контейнеров и смарпоинтеров, в которых он лежит. А сейчас сильные ссылки (shared_ptr) лишают меня такого удовольствия.

Delfigamer
> grishman
> > Оборудование и С++ никак не связаны, это заблуждение.
> Глупенький, я говорил о написании ядра ОС, драйверов и ПО микроконтроллеров.
Ядро Windows написано на Си, Linux полностью написан на Си, iOS и OS X написаны на Си и Object-C. Вполне логично что и микроконтроллеры с драйверами тоже пишутся на Си.

Delfigamer
> grishman
> > аллокация памяти в C# работает быстрее
> А вот это утверждение является фактически неверным
Пока что неверные выводы делаешь ты.
Узнай как работает менеджмент памяти в C#

Выделение памяти из управляемой кучи происходит быстрее, чем неуправляемое выделение памяти. Поскольку среда выполнения выделяет память для объекта путем добавления значения к указателю, это осуществляется почти так же быстро, как выделение памяти из стека.

Delfigamer
> grishman
> > Вообще-то смысл RAII в другом:
> Вообще-то это оно и есть, только вместо "автоматизируется" они решили сказать
> "неразрывно совмещается".
RAII - надязыковая идиома владения ресурсом, в то время как механизм конструкторов и деструкторов в С++ - это лишь возможный инструмент реализации этой идиомы. Разницу понимаешь?
Что такое RAII

Суть идиомы RAII в том, что класс инкапсулирует владение (захват и освобождение) некоторого ресурса — например, открытого файлового дескриптора.

Delfigamer
> Да не, в те времена изначальные требования к квалификации программистов были
> выше, так что к появлению крестов опытных программистов было вполне достаточно,
> чтобы начать применять язык по назначению.
Распространенное заблуждение о том, что "раньше квалификация была выше" основано на том, что раньше сама область знаний была уже, и её легче было освоить. Сейчас конца и края нет, поэтому посади специалиста из прошлого в сегодняшний день - и его всё равно придется учить.

Kartonagnick
> grishman
> > 1) Отсутствие поддержки виртуальных функций внутри конструкторов.
> во-первых, полиморфизм не перестает работать на момент работы конструктора.
> во-вторых, если вы сейчас за пыхопэшный бред - тогда потрудитесь растолковать:
> где здравый смысл?

Порядок вызова конструкторов при наследовании напомнить? Сначала базовые , затем производные. Так откуда базовому конструктору узнать о переопределенных методах в производном классе? Вот и выходит что полиморфизм в конструкторах не работает.
Пруф

Kartonagnick
> кресты - простой язык.

Правка: 6 июля 2018 21:26

Ghost2Постоялецwww6 июля 201821:24#40
grishman

> поэтому свои велосипеды тоже отсекаются

private:
    Widget* parent;

DelfigamerПостоялецwww6 июля 201821:51#41
grishman
> Так откуда базовому конструктору узнать о переопределенных методах в
> производном классе?
Он не может знать о производном классе, потому что производного класса на этот момент ещё не существует.

ardru
> > А какие вообще объекты могут осмысленно использоваться и через указатели, и
> > через переменные?
> да любые, всё зависит от контекста!
Например?

Kartonagnick
> ничто не мешает наследовать класс от enable_shared_from_this,
> а потом создавать объект на стеке.
А в чём смысл?

Правка: 6 июля 2018 22:00

DelfigamerПостоялецwww6 июля 201822:04#42
grishman
> Узнай как работает менеджмент памяти в C#
As it discovers each unreachable object, it uses a memory-copying function to compact the reachable objects in memory, freeing up the blocks of address spaces allocated to unreachable objects. Once the memory for the reachable objects has been compacted, the garbage collector makes the necessary pointer corrections so that the application's roots point to the objects in their new locations.

Ух нихрена себе быстро.

Вот ещё, смотри, как у человека всё быстро.

Правка: 6 июля 2018 22:08

KartonagnickЗабаненwww6 июля 201822:18#43
grishman
> Порядок вызова конструкторов при наследовании напомнить?
хорош тупить.
KartonagnickЗабаненwww6 июля 201822:19#44
Delfigamer
> А в чём смысл?
см выше.
Страницы: 1 2 3 4 5 6 Следующая »

/ Форум / Программирование игр / Общее

2001—2018 © GameDev.ru — Разработка игр