shared_ptr и его delete`ер
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.10.13 13:08
Оценка: :))
приветствую!

в исходниках покопался, но так и не смог понять, где ответ на мой вопрос...

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

благодарен.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: shared_ptr и его delete`ер
От: saf_e  
Дата: 08.10.13 13:33
Оценка:
Здравствуйте, niXman, Вы писали:


X>приветствую!


X>в исходниках покопался, но так и не смог понять, где ответ на мой вопрос...


X>вопрос вот в чем.

X>есть объект shared_ptr. этому объекту я устанавливаю свой delete`ер.
X>внимание вопрос: счетчик ссылок этого shared_ptr`а изменяется в момент входа в delete`ер, или в момент выхода?

X>благодарен.


Если я правильно понял ваш вопрос, то счетчик ссылок равен 0 когда вызывается делитер. т.е. он вызывается для удаления объекта.
Re[2]: shared_ptr и его delete`ер
От: ArtDenis Россия  
Дата: 08.10.13 14:47
Оценка: +1
Здравствуйте, saf_e, Вы писали:

_>Если я правильно понял ваш вопрос, то счетчик ссылок равен 0 когда вызывается делитер. т.е. он вызывается для удаления объекта.


Я бы сказал так, что как только счётчик ссылок достигает нуля, вызывается делитер.
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: shared_ptr и его delete`ер
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.10.13 16:59
Оценка: :)))
перефразирую вопрос для уточнения:
при вызове деструктора shared_ptr, декрементируется счетчик ссылок. и, если после декремента он равен нуля — вызывается делитер.

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

(я, по правде сказать, так и не нашел деструктор shared_ptr, в бустовских исходниках)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[4]: shared_ptr и его delete`ер
От: saf_e  
Дата: 08.10.13 17:01
Оценка:
Здравствуйте, niXman, Вы писали:

X>перефразирую вопрос для уточнения:

X>при вызове деструктора shared_ptr, декрементируется счетчик ссылок. и, если после декремента он равен нуля — вызывается делитер.

X>все верно?

X>таким образом, получается так, что декремент происходит до вызова делитера, а не после?
X>кто-то может с уверенностью это утверждать?

X>(я, по правде сказать, так и не нашел деструктор shared_ptr, в бустовских исходниках)


Назначение делитера -- освобождать ресурс, которым владеет shared_ptr. Теперь сами ответьте на свой вопрос
Re[5]: shared_ptr и его delete`ер
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.10.13 17:05
Оценка:
Здравствуйте, saf_e, Вы писали:

_>Назначение делитера -- освобождать ресурс, которым владеет shared_ptr. Теперь сами ответьте на свой вопрос

я не могу ответить на свой вопрос потому, что я как минимум тут вижу два возможных порядка действий:
1. сначала декрементируется счетчик, и только потом, если он равен нулю — вызывается делитер.
2. сначала проверяется значение счетчика, и если оно равно единице — вызывается делитер, и, следом за ним — декрементируется счетчик.

так какой вариант правилен?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[6]: shared_ptr и его delete`ер
От: saf_e  
Дата: 08.10.13 17:10
Оценка: +1
Здравствуйте, niXman, Вы писали:

X>Здравствуйте, saf_e, Вы писали:


_>>Назначение делитера -- освобождать ресурс, которым владеет shared_ptr. Теперь сами ответьте на свой вопрос

X>я не могу ответить на свой вопрос потому, что я как минимум тут вижу два возможных порядка действий:
X>1. сначала декрементируется счетчик, и только потом, если он равен нулю — вызывается делитер.
X>2. сначала проверяется значение счетчика, и если оно равно единице — вызывается делитер, и, следом за ним — декрементируется счетчик.

X>так какой вариант правилен?


А что поменяется с точки реализации? В любом из описанных вариантов: при удалении последнего инстанса объекта освобождается ресурс.

Лучше скажите для какого хака вам это нужно?
Re: shared_ptr и его delete`ер
От: ononim  
Дата: 08.10.13 17:11
Оценка: 9 (1) +1
X>вопрос вот в чем.
X>есть объект shared_ptr. этому объекту я устанавливаю свой delete`ер.
X>внимание вопрос: счетчик ссылок этого shared_ptr`а изменяется в момент входа в delete`ер, или в момент выхода?
я так думаю что вас это не должно беспокоить
Как много веселых ребят, и все делают велосипед...
Re: shared_ptr и его delete`ер
От: rg45 СССР  
Дата: 08.10.13 20:39
Оценка: 87 (3)
Здравствуйте, niXman, Вы писали:

X>есть объект shared_ptr. этому объекту я устанавливаю свой delete`ер.

X>внимание вопрос: счетчик ссылок этого shared_ptr`а изменяется в момент входа в delete`ер, или в момент выхода?

Счетчик — это деталь реализации умного указателя, верить в его существование, конечно, можно, но полагаться не стоит (c). Я так понимаю, вопрос в том, можно ли внутри делетера восстановить экземпляр shared_ptr'а удаляемого объекта? Здравый смысл и несложный эксперимент подсказывают, что нет:

http://ideone.com/IIw8FU#sthash.dANBEuoG.eurfLEHz.dpuf

#include <iostream>
#include <memory>

int main() 
{
    std::weak_ptr<int> weakPtr;
    auto deleter = [&](int* targetPtr) 
    {
        std::cout 
            << "- Can we restore a shared pointer in its deleter?\n"
            << "- " << (weakPtr.lock().get() ? "Yes." : "No.") << std::endl;
        delete targetPtr;
    };
    std::shared_ptr<int> sharedPtr(new int(), deleter);
    weakPtr = sharedPtr;
    std::cout 
        << "- Has the shared pointer been created?\n"
        << "- " << (weakPtr.lock().get() ? "Yes." : "No.") << std::endl;
}

Output:
- Has the shared pointer been created?
- Yes.
- Can we restore a shared pointer in its deleter?
- No.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: shared_ptr и его delete`ер
От: niXman Ниоткуда https://github.com/niXman
Дата: 09.10.13 05:51
Оценка:
спасибо всем за ответы.

на самом деле, мой вопрос важен в двух случаях:
1. когда производится попытка восстановить shared_ptr из делитера.
2. когда делитер бросает исключение(знаю, что в доке сказано что он не должен этого делать), и, таким образом, если декремент производится после — получаем некорректное состояние.

мой случай первый.

всем спасибо, вопрос закрыт.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: shared_ptr и его delete`ер
От: rg45 СССР  
Дата: 09.10.13 07:19
Оценка:
Здравствуйте, niXman, Вы писали:

X>на самом деле, мой вопрос важен в двух случаях:

X>1. когда производится попытка восстановить shared_ptr из делитера.
X>2. когда делитер бросает исключение(знаю, что в доке сказано что он не должен этого делать), и, таким образом, если декремент производится после — получаем некорректное состояние.

Второй случай, на мой взгляд, заслуживает отдельного рассмотрения. Лично у меня до сих пор не сложилось какого-то универсального понимания того, как, все-таки, следует обрабатывать ошибки, обнаруженные в деструкторах (и др. функциях освобождения ресурсов). В стандарте есть следующая рекомендация:

15.2/3
The process of calling destructors for automatic objects constructed on the path from a try block to a throw-expression is called “stack unwinding.” If a destructor called during stack unwinding exits with an exception, std::terminate is called (15.5.1). [ Note: So destructors should generally catch exceptions and not let them propagate out of the destructor. —end note ]

Классики пишут (Саттер, Александреску, "Coding standards..."):

Chapter 51. Destructors, deallocation, and swap never fail
. . .
Fortunately, when releasing a resource, the scope for failure is definitely smaller. If using exceptions as the error reporting mechanism, make sure such functions handle all exceptions and other errors that their internal processing might generate. (For exceptions, simply wrap everything sensitive that your destructor does in a try/catch(…) block.) This is particularly important because a destructor might be called in a crisis situation, such as failure to allocate a system resource (e.g., memory, files, locks, ports, windows, or other system objects).

Таким образом, следуя этим рекомендациям, вызов делетера в деструкторе shared_ptr следовало бы обернуть в try/catch(…)?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: shared_ptr и его delete`ер
От: niXman Ниоткуда https://github.com/niXman
Дата: 09.10.13 07:45
Оценка:
Здравствуйте, rg45, Вы писали:

R>Лично у меня до сих пор не сложилось какого-то универсального понимания того, как, все-таки, следует обрабатывать ошибки, обнаруженные в деструкторах

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

R>Таким образом, следуя этим рекомендациям, вызов делетера в деструкторе shared_ptr следовало бы обернуть в try/catch(…)?

получается так.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[5]: shared_ptr и его delete`ер
От: rg45 СССР  
Дата: 09.10.13 08:11
Оценка:
Здравствуйте, niXman, Вы писали:

R>>Таким образом, следуя этим рекомендациям, вызов делетера в деструкторе shared_ptr следовало бы обернуть в try/catch(…)?

X>получается так.

Да, но почему-то этого не делают. Я, по крайней мере, не знаю ни одной реализации shared_ptr, где бы это делалось. Да и, честно говоря, был бы удивлен, если бы это делалось — тупо давить все исключения на уровне библиотеки общего применения — это как-то странно.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: shared_ptr и его delete`ер
От: niXman Ниоткуда https://github.com/niXman
Дата: 09.10.13 08:16
Оценка:
Здравствуйте, rg45, Вы писали:

R>Да, но почему-то этого не делают. Я, по крайней мере, не знаю ни одной реализации shared_ptr, где бы это делалось. Да и, честно говоря, был бы удивлен, если бы это делалось — тупо давить все исключения на уровне библиотеки общего применения — это как-то странно.


согласен.
тут, я думаю, могли бы поступить таким образом: вызов делитера обернуть в try{}catch, и в catch-блоке делать вывод exception::what() в stderr, и спокойно ассертится.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[6]: shared_ptr и его delete`ер
От: saf_e  
Дата: 09.10.13 08:19
Оценка: 1 (1) +1
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, niXman, Вы писали:


R>>>Таким образом, следуя этим рекомендациям, вызов делетера в деструкторе shared_ptr следовало бы обернуть в try/catch(…)?

X>>получается так.

R>Да, но почему-то этого не делают. Я, по крайней мере, не знаю ни одной реализации shared_ptr, где бы это делалось. Да и, честно говоря, был бы удивлен, если бы это делалось — тупо давить все исключения на уровне библиотеки общего применения — это как-то странно.


А что толку от try/catch(…)? Если в результате освобождения ресурса произошла критическая ошибка (достойная выброса исключения), то его и надо бросать.
Скорее всего это приведет к выполнению стандартных механизмов ловли исключений в приложении, или крешу, оба варианта лучше чем "тихо" словить, или вывести в лог.
Re[7]: shared_ptr и его delete`ер
От: rg45 СССР  
Дата: 09.10.13 08:24
Оценка:
Здравствуйте, saf_e, Вы писали:

R>>>>Таким образом, следуя этим рекомендациям, вызов делетера в деструкторе shared_ptr следовало бы обернуть в try/catch(…)?

X>>>получается так.

R>>Да, но почему-то этого не делают. Я, по крайней мере, не знаю ни одной реализации shared_ptr, где бы это делалось. Да и, честно говоря, был бы удивлен, если бы это делалось — тупо давить все исключения на уровне библиотеки общего применения — это как-то странно.


_>А что толку от try/catch(…)? Если в результате освобождения ресурса произошла критическая ошибка (достойная выброса исключения), то его и надо бросать.

_>Скорее всего это приведет к выполнению стандартных механизмов ловли исключений в приложении, или крешу, оба варианта лучше чем "тихо" словить, или вывести в лог.

Согласен, рассуждение здравое. Как в таком случае воспринимать рекомендации классиков и стандарта? Может быть, они просто неудачно выразились, а на самом деле имели в виду что-то другое?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[8]: shared_ptr и его delete`ер
От: saf_e  
Дата: 09.10.13 08:27
Оценка: 1 (1) +1
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, saf_e, Вы писали:


R>>>>>Таким образом, следуя этим рекомендациям, вызов делетера в деструкторе shared_ptr следовало бы обернуть в try/catch(…)?

X>>>>получается так.

R>>>Да, но почему-то этого не делают. Я, по крайней мере, не знаю ни одной реализации shared_ptr, где бы это делалось. Да и, честно говоря, был бы удивлен, если бы это делалось — тупо давить все исключения на уровне библиотеки общего применения — это как-то странно.


_>>А что толку от try/catch(…)? Если в результате освобождения ресурса произошла критическая ошибка (достойная выброса исключения), то его и надо бросать.

_>>Скорее всего это приведет к выполнению стандартных механизмов ловли исключений в приложении, или крешу, оба варианта лучше чем "тихо" словить, или вывести в лог.

R>Согласен, рассуждение здравое. Как в таком случае воспринимать рекомендации классиков и стандарта? Может быть, они просто неудачно выразились, а на самом деле имели в виду что-то другое?


Бросать исключения из деструктора идея неудачная, по понятным причинам. Но и городить try/catch(...) еще более неудачная как по мне.
Соответственно, пишущий делитер должен понимать свою ответственность в этом важном деле И если он решил бросить исключение, то нам остается только наедятся, что он знает что делает.

Но мешать ему в этом, я бы точно не стал
Re[7]: shared_ptr и его delete`ер
От: Vain Россия google.ru
Дата: 10.10.13 07:51
Оценка:
Здравствуйте, saf_e, Вы писали:

_>А что толку от try/catch(…)? Если в результате освобождения ресурса произошла критическая ошибка (достойная выброса исключения), то его и надо бросать.

_>Скорее всего это приведет к выполнению стандартных механизмов ловли исключений в приложении, или крешу, оба варианта лучше чем "тихо" словить, или вывести в лог.
В лог выводят здесь не потому чтобы тихо выйти, а потому что раельный стектрейс при креше (если он произойдёт) может быть абсолютно бесполезен. А так вы получити стектрейс и приложение возможно будет работать дальше не падая. А когда упадёт — реальное место ошибки будет уже заготовлено.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[8]: shared_ptr и его delete`ер
От: saf_e  
Дата: 10.10.13 07:55
Оценка:
Здравствуйте, Vain, Вы писали:

V>Здравствуйте, saf_e, Вы писали:


_>>А что толку от try/catch(…)? Если в результате освобождения ресурса произошла критическая ошибка (достойная выброса исключения), то его и надо бросать.

_>>Скорее всего это приведет к выполнению стандартных механизмов ловли исключений в приложении, или крешу, оба варианта лучше чем "тихо" словить, или вывести в лог.
V>В лог выводят здесь не потому чтобы тихо выйти, а потому что раельный стектрейс при креше (если он произойдёт) может быть абсолютно бесполезен. А так вы получити стектрейс и приложение возможно будет работать дальше не падая. А когда упадёт — реальное место ошибки будет уже заготовлено.

Еще раз, бросать или не бросать (вызывать креш-хендлер, писать лог, или отсылать письмо) это ваше решение, как автора делитера.
Шаред-птр, просто не должен вам мешать.

На самом деле ошибки при освобождении ресурса это что-то мифическое.
Re[9]: shared_ptr и его delete`ер
От: enji  
Дата: 10.10.13 09:35
Оценка:
Здравствуйте, saf_e, Вы писали:

_>На самом деле ошибки при освобождении ресурса это что-то мифическое.


Да почему, только недавно напоролся в sqlitepp. В деструкторе транзакции она откатывалась (если не была закоммичена), при этом происходила ошибка БД и кидалось исключение.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.