LINUX.ORG.RU

удаление shared_ptr, без удаления объекта внутри

 ,


1

2

Например есть функция принимающая указатель на объект. Есть shared_ptr в котором лежит объект. Иногда необходимо передать указатель на объект какой либо функции, которая принимает ТОЛЬКО указатель, и жизнь объекта должна продолжиться внутри функции, а умный указатель займет другой объект и тот который мы передадим в функцию удалиться. Как этого избежать?

При создании указателя передавай ему самописный Deleter, который будет разруливать такие ситуации

Gvidon ★★★★
()

Можно написать обертку для функции принимающей указатель в которую будет передаваться shared_ptr

urquan
()

Можно не вы???ваться и не использовать shared_ptr =)

UVV ★★★★★
()

Иногда необходимо передать указатель на объект какой либо функции, которая принимает ТОЛЬКО указатель, и жизнь объекта должна продолжиться внутри функции, а умный указатель займет другой объект и тот который мы передадим в функцию удалиться. Как этого избежать?

сделать копию shared_ptr::operator=(), и эту копию передать в функцию.

drBatty ★★
()

Возможность изменить функцию отсутствует, как я понимаю? У себя внутри она, в конце концов, удалит объект, на который смотрит переданный ей указатель?

one_more_hokum ★★★
()
Ответ на: комментарий от Gvidon

Никогда не пользовался shared_ptr, но выглядеть, на мой взгляд, это будет как-то так:

struct MyDeleter
{
  MyDeleter(): del(true) {}
  void operator()(void *ptr)
  {
     if (del)
       delete ptr;
  }
  void setDelete(bool d)
  {
    del = d;
  }
private:
  bool del;
};

///////////// Где-то в коде

std::shared_ptr<MyClass> ptr(new MyClass(), MyDeleter());
foo(ptr->get());
std::get_deleter(ptr)->setDelete(false);
ptr.reset(); // С объектом ничего не происходит

Gvidon ★★★★
()
Ответ на: комментарий от aol

в программе я разруливаю все действия с объектом, но есть ситуации когда объект передается старому коду, и какое-то время должен жить там

pozitiffcat ★★★
() автор топика
Ответ на: комментарий от Gvidon

в tr1 какое-то неадекватное get_deleter

// 2.2.3.10 shared_ptr get_deleter (experimental)
  template<typename _Del, typename _Tp, _Lock_policy _Lp>
    inline _Del*
    get_deleter(const __shared_ptr<_Tp, _Lp>& __p)
    {
#ifdef __GXX_RTTI
      return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del)));
#else
      return 0;
#endif
    }
как это понимать? так и не удалось завести (((

pozitiffcat ★★★
() автор топика
Ответ на: комментарий от pozitiffcat

все разобрался нормально там все работает

pozitiffcat ★★★
() автор топика

кому интересно

namespace std{
namespace tr1{

/**
 * @brief обработчик удалятора в умном указателе, иногда нужно не удалять объект под указателем
 */
struct SmartDeleter
{
  SmartDeleter(): del(true) {}
  template <typename T>
  void operator()(T *ptr)
  {
     if (del)
       delete ptr;
  }
  void SetDelete(bool d)
  {
    del = d;
  }
private:
  bool del;
};

template <typename T>
/**
 * @brief сказать умному указателю, что его удалять не надо (работает для объектов созданных через new_shared)
 * @param ptr умный указатель
 */
inline void no_delete_shared(T &ptr)
{
    std::tr1::get_deleter<SmartDeleter>(ptr)->SetDelete(false);
}

template <typename T>
inline std::tr1::shared_ptr<T> new_shared()
{
  return std::tr1::shared_ptr<T>(new T(), SmartDeleter());
}
template <typename T, typename Arg1>
inline std::tr1::shared_ptr<T> new_shared(Arg1 arg1)
{
  return std::tr1::shared_ptr<T>(new T(arg1), SmartDeleter());
}
template <typename T, typename Arg1, typename Arg2>
inline std::tr1::shared_ptr<T> new_shared(Arg1 arg1, Arg2 arg2)
{
    return std::tr1::shared_ptr<T>(new T(arg1, arg2), SmartDeleter());
}
template <typename T, typename Arg1, typename Arg2, typename Arg3>
inline std::tr1::shared_ptr<T> new_shared(Arg1 arg1, Arg2 arg2, Arg3 arg3)
{
    return std::tr1::shared_ptr<T>(new T(arg1, arg2), SmartDeleter());
}
template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
inline std::tr1::shared_ptr<T> new_shared(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
{
    return std::tr1::shared_ptr<T>(new T(arg1, arg2), SmartDeleter());
}
template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
inline std::tr1::shared_ptr<T> new_shared(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
{
    return std::tr1::shared_ptr<T>(new T(arg1, arg2), SmartDeleter());
}
template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
inline std::tr1::shared_ptr<T> new_shared(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6)
{
    return std::tr1::shared_ptr<T>(new T(arg1, arg2), SmartDeleter());
}


}
}

pozitiffcat ★★★
() автор топика
Ответ на: комментарий от pozitiffcat

У меня вот такой вариант завёлся:

#include <iostream>
#include <tr1/memory>

struct MyDeleter
{
  MyDeleter(): del(true) {}

  template <typename T>
  void operator()(T * ptr)
  {
    if (del)
      delete ptr;
  }

  void setDelete(bool d)
  {
    del = d;
  }
private:
  bool del;
};

struct MyClass
{
  MyClass(const std::string &s): str(s) {}
  void say()
  {
    std::cout << str << std::endl;
  }
private:
  std::string str;
};

int main()
{
  MyClass *c_ptr = new MyClass("hello");
  std::tr1::shared_ptr<MyClass> ptr(c_ptr, MyDeleter());
  MyDeleter *deltr = std::tr1::get_deleter<MyDeleter, MyClass>(ptr);
  std::cout << deltr << std::endl;
  if (deltr)
    deltr->setDelete(false);
  ptr.reset();
  c_ptr->say();
}

Gvidon ★★★★
()
Последнее исправление: Gvidon (всего исправлений: 1)

жизнь объекта должна продолжиться внутри функции

Это как?

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

Вы, случайно, не путаете с auto_ptr?

no-such-file ★★★★★
()

ничего не понял, можешь еще раз?

и жизнь объекта должна продолжиться внутри функции

ну и что с ним должно будет потом?

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

это как?

Boy_from_Jungle ★★★★
()

угадай-автора-по-сабжу тред

Stil ★★★★★
()
Ответ на: комментарий от pozitiffcat

deleter не позволяет использовать make_shared, который работает быстрее, а у тебя вообще что-то напутано, насколько я нопял тебе лучше будет с auto_ptr or scoped_ptr

Boy_from_Jungle ★★★★
()

shareg_ptr::get() передаёшь в старый код и храниш shared_ptr в автоматической памяти (в статическом std::list например) до того момента, когда станет известно, что указатель в старом коде больше не используется. после этого shared_ptr удаляешь.

nanoolinux ★★★★
()
Ответ на: комментарий от pozitiffcat

и какое-то время должен жить

Если это время хоть как-то детерменированно - делай обертку, которая будет хранить копию shared_ptr, пока указатель находится в глубинах старого кода.

Если после передачи указателя в ф-ию он больше нигде не нужен - создайте копию объекта в динамической памяти и передайте указатель на нее.

anonymous
()

Использовать, например boost::intrusive_ptr как основу для своего указателя со счетчиком ссылок.

shared_ptr по своей логике не может отдать владение. Поскольку для этого надо модифицировать инвариант всех существующих shared_ptr которые ссылаются на твой объект.

Как менее радикальный вариант — рекомендую присмотреться, возможно там можно обойтись без разделяемого владения? И auto_ptr и unique_ptr позволяют забрать из них владение

Remington
()
Ответ на: комментарий от Gvidon

Честно говоря, не понял, что делают ваши велосипедные делетеры. Вы что ли пытаетесть вручную управлять впеменем жизни объекта, который лежит в shared_ptr? Какой тогда смысл в shared_ptr? Что будет, если единственный shared_ptr будет ресетнут, пока в вашем делетере false? Мемлик?

ratatosk
()
Ответ на: комментарий от ratatosk

Можно сделать обертку через вложенный boost::bind, таким образом копия shared_ptr будет сохранена в замыкании.

#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>

struct A {
  A(const std::string &s) : str(s) {}
  std::string str;
};

void f(A *a) {
  std::cout << a->str << std::endl;
}

int main() {
  typedef boost::shared_ptr<A> a_ptr;
  a_ptr a(new A("hello world"));
  boost::bind(&f, boost::bind(&a_ptr::get, a))();
}

ratatosk
()

Хотя, если честно, я не понял, кто будет ресетить этот указатель. Другой тред? Тогда почему просто в вызывающей функции не сделать копию...

ratatosk
()
Ответ на: комментарий от pozitiffcat

Автор, не мучай, удовлетвори мое любопытство, кто ресетит умный указатель, почему вызывающий не может иметь копию на время вызова, и кто освободит указатель, если ваш самописный делетер будет вызван, когда del == false?

ratatosk
()
Ответ на: комментарий от ratatosk

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

pozitiffcat ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.