Здравствуйте, Аноним, Вы писали:
А>Здравствуйте! А>Расскажите пожалуйста про практическое применение unique_ptr. Не могу понять в каких случаях он нужен. Все примеры в инете абстрактные и демонститруют лишь свойства этого указателя, а не реальные задачи где без него не обойтись
// Пример 1: возврат объекта из фабрики
std::unique_ptr<CriticleSectionLock> lock(CriticleSection& sec)
{
return std::unique_ptr<CriticleSectionLock>( new CriticleSectionLock(sec) );
}
void foo(
Resource A, CriticleSection* protectA, // ресурс возможно защищен критической секцией, а может и нет....
Resource B, CriticleSection* protectB)
{
std::unique_ptr<CriticleSectionLock> lockA, lockB;
// Пример 2: условное создание объекта:
// Не переменная на стеке потому что есть условие на создание.
// Не shared_ptr потому что не нужен его overhead.if(protectA)
lockA = lock(*protectA);
if(protectB && protectA!=protectB )
lockB = lock(*protectB);
// Что-то делаем с А и B.
}
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте! А>Расскажите пожалуйста про практическое применение unique_ptr. Не могу понять в каких случаях он нужен. Все примеры в инете абстрактные и демонститруют лишь свойства этого указателя, а не реальные задачи где без него не обойтись
Здравствуйте, Chorkov, Вы писали:
C>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте! А>>Расскажите пожалуйста про практическое применение unique_ptr. Не могу понять в каких случаях он нужен. Все примеры в инете абстрактные и демонститруют лишь свойства этого указателя, а не реальные задачи где без него не обойтись
C>
C> // Пример 1: возврат объекта из фабрики
C> std::unique_ptr<CriticleSectionLock> lock(CriticleSection& sec)
C> {
C> return std::unique_ptr<CriticleSectionLock>( new CriticleSectionLock(sec) );
C> }
C> void foo(
C> Resource A, CriticleSection* protectA, // ресурс возможно защищен критической секцией, а может и нет....
C> Resource B, CriticleSection* protectB)
C> {
C> std::unique_ptr<CriticleSectionLock> lockA, lockB;
C> // Пример 2: условное создание объекта:
C> // Не переменная на стеке потому что есть условие на создание.
C> // Не shared_ptr потому что не нужен его overhead.
C> if(protectA)
C> lockA = lock(*protectA);
C> if(protectB && protectA!=protectB )
C> lockB = lock(*protectB);
C> // Что-то делаем с А и B.
C> }
C>
а зачем тут вообще "new" CriticleSectionLock ?? Почему бы просто CriticleSectionLock не вернуть? безо всяких указателей??
Применение unique_ptr
От:
Аноним
Дата:
12.03.14 06:06
Оценка:
Здравствуйте!
Расскажите пожалуйста про практическое применение unique_ptr. Не могу понять в каких случаях он нужен. Все примеры в инете абстрактные и демонститруют лишь свойства этого указателя, а не реальные задачи где без него не обойтись
Здравствуйте, jazzer, Вы писали:
J>Он нужен, чтоб не звать delete руками.
Это понятно. shared_ptr тоже нужен чтобы не делать delete руками, но с ним понятно — что-то типа указателя со сборкой мусора на подсчете ссылок.
Меня интересуют практические, архитектурные области применения unique_ptr.
Здравствуйте, Άнoним, Вы писали:
Ά>Здравствуйте, jazzer, Вы писали:
J>>Он нужен, чтоб не звать delete руками.
Ά>Это понятно. shared_ptr тоже нужен чтобы не делать delete руками, но с ним понятно — что-то типа указателя со сборкой мусора на подсчете ссылок.
Так из названия же видно.
shared_ptr — для совместного владения, когда на объект может указывать много shared_ptr (можно создавать копии) и объект убивают, только когда все ссылки помрут.
unique_ptr — уникален, т.е. нескольких unique_ptr, указывающих на один и тот же объект, быть не может (копирование запрещено). Но при этом разрешена передача владения от одного unique_ptr другому, с одновременным уничтожением первого.
Ά>Меня интересуют практические, архитектурные области применения unique_ptr.
Архитектурно — везде, где у тебя в программе есть владеющий указатель (т.е. по которому ты зовешь delete, когда он тебе больше не нужен) и он ровно один для каждого объекта, на который он указывает, имеет смысл вместо голого указателя использовать unique_ptr.
Еще один сценарий — функции-фабрики, возвращающие указатель на вновь созданный объект. Такой указатель тоже имеет смысл возвращать как unique_ptr — тогда он гарантировано помрет, даже если результат по какой-то причине не будет использован (например, из-за исключенияв неподходящий момент).
Здравствуйте, Chorkov, Вы писали:
C>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте! А>>Расскажите пожалуйста про практическое применение unique_ptr. Не могу понять в каких случаях он нужен. Все примеры в инете абстрактные и демонститруют лишь свойства этого указателя, а не реальные задачи где без него не обойтись
C>
C> // Пример 1: возврат объекта из фабрики
C> std::unique_ptr<CriticleSectionLock> lock(CriticleSection& sec)
C> {
C> return std::unique_ptr<CriticleSectionLock>( new CriticleSectionLock(sec) );
C> }
C> void foo(
C> Resource A, CriticleSection* protectA, // ресурс возможно защищен критической секцией, а может и нет....
C> Resource B, CriticleSection* protectB)
C> {
C> std::unique_ptr<CriticleSectionLock> lockA, lockB;
C> // Пример 2: условное создание объекта:
C> // Не переменная на стеке потому что есть условие на создание.
C> // Не shared_ptr потому что не нужен его overhead.
C> if(protectA)
C> lockA = lock(*protectA);
C> if(protectB && protectA!=protectB )
C> lockB = lock(*protectB);
C> // Что-то делаем с А и B.
C> }
C>
lol @ "Criticle"
вообще-то есть всякие std::mutex, std::*_lock
и если вместо них использовать unique_ptr, то new не нужен, нужен deleter
std::unique_ptr<CriticleSectionLock, void(*)(CriticleSection*)> lock(CriticleSection* sec)
{
if (sec) sec->lock();
return {sec, [](CriticleSection* sec){ if (sec) sec->unlock(); }};
}
ИМХО, конечно... но С++'11 читабельности не добавляет.
A>
A>std::unique_ptr<CriticleSectionLock, void(*)(CriticleSection*)> lock(CriticleSection* sec)
A>{
A> if (sec) sec->lock();
A> return {sec, [](CriticleSection* sec){ if (sec) sec->unlock(); }};
A>}
A>
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, jazzer, Вы писали:
J>Архитектурно — везде, где у тебя в программе есть владеющий указатель (т.е. по которому ты зовешь delete, когда он тебе больше не нужен) и он ровно один для каждого объекта, на который он указывает, имеет смысл вместо голого указателя использовать unique_ptr.
У меня практически везде "владеющие" указатели. Т.е. есть какой-то класс, в нем указатель на что-то другое, в конструкторе создается объект и в деструкторе удаляется. Никто больше его удалить не может. Но я вот чего не понимаю: этот unique_ptr можно только перемещать. Как же я в таком случае отдам адрес объекта, на который указывает unique_ptr, кому-то для каких-то действий, если его передавать как аргумент функции нельзя???
А если я его преобразую к обычному указателю и передам, то в чем тогда смысл уникальности?
Здравствуйте, Άнoним, Вы писали:
Ά>У меня практически везде "владеющие" указатели. Т.е. есть какой-то класс, в нем указатель на что-то другое, в конструкторе создается объект и в деструкторе удаляется. Никто больше его удалить не может.
Но в процессе эволюции кода явное удаление в деструкторе может потерятся. Лишняя мелочь, слежение за которой можно возложить на компилятор.
Ά>Но я вот чего не понимаю: этот unique_ptr можно только перемещать. Как же я в таком случае отдам адрес объекта, на который указывает unique_ptr, кому-то для каких-то действий, если его передавать как аргумент функции нельзя???
Ά>А если я его преобразую к обычному указателю и передам, то в чем тогда смысл уникальности?
Если для владеющих указателей использовать raii обертки (unique для уникальных, shared для разделяемых и т.д.), то в коде не остается явных вызовов delete. И тогда можно для себя ввести правило, что голый указатель — он всегда не владеющий.
Здравствуйте, Άнoним, Вы писали:
Ά>Здравствуйте, jazzer, Вы писали:
J>>Архитектурно — везде, где у тебя в программе есть владеющий указатель (т.е. по которому ты зовешь delete, когда он тебе больше не нужен) и он ровно один для каждого объекта, на который он указывает, имеет смысл вместо голого указателя использовать unique_ptr.
Ά>У меня практически везде "владеющие" указатели. Т.е. есть какой-то класс, в нем указатель на что-то другое, в конструкторе создается объект и в деструкторе удаляется. Никто больше его удалить не может.
Тогда unique_ptr — то, что надо.
Ά>Но я вот чего не понимаю: этот unique_ptr можно только перемещать. Как же я в таком случае отдам адрес объекта, на который указывает unique_ptr, кому-то для каких-то действий, если его передавать как аргумент функции нельзя???
Для каких действий? Связанных с владением/временем жизни (удаление, создание копий указателей и т.п.) или просто поменять данные/подергать методы?
Если первое — тогда у тебя что-то не так с архитектурной точки зрения.
Если второе — есть метод get(), который даст тебе голый указатель. Рулез в том, что этот вызов явный и локальный — то есть ничего никуда не утечет и все вызовы можно отследить.
Ά>А если я его преобразую к обычному указателю и передам, то в чем тогда смысл уникальности?
Такого преобразования нет. Есть метод get() — он возвращает невладеющий указатель. Уникальность владеющего указателя остается в силе. А тебе надо в программе гарантировать, что не будет невладеющих указателей к моменту смерти владеющего.
Здравствуйте, jazzer, Вы писали:
J>Такого преобразования нет. Есть метод get() — он возвращает невладеющий указатель. Уникальность владеющего указателя остается в силе. А тебе надо в программе гарантировать, что не будет невладеющих указателей к моменту смерти владеющего.
Таким образом, если я правильно понял вас и rusted, все что делает уникальный указатель — это просто обеспечивает автоматическое удаление своего объекта, и предоставляет некоторую "защиту от дурака" в виде запрета копирования себя? Получение обычных указателей из unique_ptr — нормальная практика. Никакой защиты от того, что я вызову delete для полученного указателя, язык не предоставляет, а все основывается только на негласном соглашении "если нигде не использовать явно new/delete воообще, то все будет хорошо".
Я правильно понимаю?
Здравствуйте, Άнoним, Вы писали:
Ά>Здравствуйте, jazzer, Вы писали:
J>>Такого преобразования нет. Есть метод get() — он возвращает невладеющий указатель. Уникальность владеющего указателя остается в силе. А тебе надо в программе гарантировать, что не будет невладеющих указателей к моменту смерти владеющего.
Ά>Таким образом, если я правильно понял вас и rusted, все что делает уникальный указатель — это просто обеспечивает автоматическое удаление своего объекта, и предоставляет некоторую "защиту от дурака" в виде запрета копирования себя? Получение обычных указателей из unique_ptr — нормальная практика. Никакой защиты от того, что я вызову delete для полученного указателя, язык не предоставляет, а все основывается только на негласном соглашении "если нигде не использовать явно new/delete воообще, то все будет хорошо". Ά>Я правильно понимаю?
Да.
rusted все правильно сказал: "можно для себя ввести правило, что голый указатель — он всегда не владеющий."
Если у тебя код типа такого:
то никаких проблем нет — голый указатель возник и изчез, его жизнь ограничена вызовом функции f( p.get() ).
Таким образом, остается только гарантировать, что никто не создает уникальные указатели из голых, если только не известно достоверно, что это свежесозданный объект и им никто больше не управляет (например, это верно для указателя, который возвращает new).