В целях обучения я пытаюсь написать собственный смарт-указатель, имитирующий std::shared_ptr
. У меня есть static std::map<void *, int> ref_track
, который отслеживает, есть ли еще общий указатель, ссылающийся на определенный блок в памяти.Ошибка сегментации в деструкторе собственного общего указателя
Моя концепция такова:
template <typename PType>
class shared_ptr
{
public:
shared_ptr()
: value_(nullptr), ptr_(nullptr)
{}
template <typename T>
explicit shared_ptr(T * ptr)
: shared_ptr()
{
reset(ptr);
}
template <typename T>
shared_ptr(shared_ptr<T> const & other)
: shared_ptr()
{
reset(other.get());
}
~shared_ptr()
{
reset();
}
void reset()
{
if(value_)
{
delete value_; // Segmentation fault here!
value_ = 0;
ptr_ = 0;
}
}
template <typename T>
void reset(T * ptr)
{
reset();
if(ptr)
{
value_ = new shared_ptr_internal::storage_impl<
T
>(ptr);
ptr_ = ptr;
}
}
PType * get() const
{
return ptr_;
}
typename shared_ptr_internal::ptr_trait<PType>::type operator *()
{
return *ptr_;
}
private:
shared_ptr_internal::storage_base * value_;
PType * ptr_;
};
При запуске мой набор тестов, я заметил, что
shared_ptr<int> a(new int(42));
a.reset(new int(13));
работает отлично, но
shared_ptr<int> a(new int(42));
a = shared_ptr<int>(new int(13));
приводит к проблемам: *a
является 0
вместо 13
и delete value_
с ошибкой сегментации в деструкторе a
. Я отметил крах в исходном коде с комментарием.
Используемые внутренние классы
namespace shared_ptr_internal
{
typedef std::map<void *, int> ref_tracker;
typedef std::map<void *, int>::iterator ref_tracker_iterator;
typedef std::pair<void *, int> ref_tracker_entry;
static ref_tracker ref_track;
struct storage_base
{
virtual ~storage_base() {}
};
template <typename PType>
struct storage_impl : storage_base
{
storage_impl(PType * ptr)
: ptr_(ptr)
{
ref_tracker_iterator pos = ref_track.find(ptr);
if(pos == ref_track.end())
{
ref_track.insert(
ref_tracker_entry(ptr, 1)
);
}
else
{
++pos->second;
}
}
~storage_impl()
{
ref_tracker_iterator pos = ref_track.find(ptr_);
if(pos->second == 1)
{
ref_track.erase(pos);
delete ptr_;
}
else
{
--pos->second;
}
}
private:
PType * ptr_;
};
template <typename PType>
struct ptr_trait
{
typedef PType & type;
};
template <>
struct ptr_trait<void>
{
typedef void type;
};
}
Извините за большую часть исходного кода, но я действительно не знаю, как я мог бы сузить ее дальше. Я был бы признателен за любые идеи, которые могут вызывать segfault, и более того, почему это не происходит при использовании сброса вручную.
Update
Мой (не работоспособный) оператор присваивания:
template <typename T>
shared_ptr<PType> & operator =(shared_ptr<T> const & other)
{
if(this != &other)
{
value_ = nullptr;
ptr_ = nullptr;
reset(other.get());
}
return *this;
}
вы можете попробовать 'gdb' или другие отладчики для отладки. – phoxis
«У меня есть статический зЬй :: Карта ref_track что отслеживает», что кажется плохой идеей, и ненужный –
stijn
оффтоп: 'шаблон shared_ptr (shared_ptr константный и другие) : shared_ptr() { сброса (other.get()); } 'не следует компилировать. Вы вызываете конструктор из другого? –
fritzone