Программисты, использующие boost::shared_ptr
нужно избегать циклов, чтобы утечка ресурсов не создавалась. Общий совет заключается в использовании boost::weak_ptr
в тех случаях, когда такой цикл может быть создан. Однако это создает разрыв в намерении, когда можно было бы использовать shared_ptr
но не сделал это только из-за проблемы цикла.
Однако мне кажется, что должна быть возможность создать специальный вид shared_ptr, который позволяет избежать проблемы цикла, связывая счетчик ссылок всех указателей в цикле. И поскольку я могу придумать, как это сделать, мне интересно, существует ли такая вещь?
Чтобы доказать, что я не сумасшедший или, может быть, я такой, я предлагаю следующее плохо продуманное и уродливое доказательство концепции:
#define BOOST_NO_MEMBER_TEMPLATE_FRIENDS
#include <boost/shared_ptr.hpp>
#include <iostream>
template <typename T>
struct shared_count_ptr
{
boost::shared_ptr<T> innerPtr;
template <typename TT>
void link( boost::shared_ptr<T> & sharedPtr, boost::shared_ptr<TT> & linked )
{
innerPtr = sharedPtr;
innerPtr.pn = linked.pn;
}
};
struct Hand;
struct Arm
{
Arm() { std::cout << "Creating Arm\n"; }
~Arm() { std::cout << "Destroying Arm\n"; }
shared_count_ptr<Hand> hand;
};
struct Hand
{
Hand() { std::cout << "Creating Hand\n"; }
~Hand() { std::cout << "Destroying Hand\n"; }
shared_count_ptr<Arm> arm;
};
int main()
{
boost::shared_ptr<Arm> savedArm;
std::cout << "Scope 0 entered\n";
{
std::cout << "\tScope 1 entered\n" ;
boost::shared_ptr<Arm> arm( new Arm );
{
std::cout << "\t\tScope 2 entered\n";
boost::shared_ptr<Hand> hand( new Hand );
hand->arm.link( arm, arm->hand );
arm->hand.innerPtr = hand;
savedArm = arm;
}
std::cout << "\t\tScope 2 exited\n";
}
std::cout << "\tScope 1 exited\n";
std::cout << "\tScope 0 about to exit\n";
return 0;
}
Общая концепция заключается в том, что в глазах воображаемого shared_count_ptr
Рука и рука — фактически один и тот же объект.
Так:
boost
?Вот простой тест. Создайте полный граф на 17 вершинах так, чтобы программа указывала только на вершину 0. Начните удалять ребра случайным образом. Ваша идея работает? (Спойлер: это не так).
Я бы вообразил тебя мог сделать что-то в этом направлении. Однако в такой структуре каждый указатель A
должен знать о каждом другом указателе B
, такой что либо B
может быть достигнуто с A
или наоборот. Я не понимаю, как это может масштабироваться до более чем небольшого числа взаимосвязанных указателей.
Казалось бы, если вы хотите поддерживать циклические ссылки без какой-либо помощи со стороны программиста, вам более или менее нужен полноценный сборщик мусора, а не простая схема подсчета ссылок (я бы хотел, чтобы в этом ошиблись).