Путаница в отношении boost :: shared_ptr - PullRequest
0 голосов
/ 08 декабря 2010

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

Рассмотрим случай с лицом , у которого есть сотрудник . Сотрудник внутренне поддерживает всех своих сотрудников в vector< shared_ptr< Person > >. Из-за этого передовые практики диктуют, что любой интерфейс с участием Person должен быть обернутым лицом shared_ptr?

Например, все или только некоторые из них в порядке:

Person Employeer::getPresidentCopy();
Person& Employeer::getPresidentRef();
Person* Employeer::getPresidentRawPtr();
shared_ptr<Person> Employeer::getPresidentSharedPtr();

Или, например:

void Employeer::hireByCopy(Person p);
void Employeer::hireByRef(Person& p);
void Employeer::hireByRawPtr(Person* p);
void Employeer::hireBySharedPtr(shared_ptr<Person> p);

Если позже я захочу изменить реализацию на использование johns_very_own_shared_ptr вместо разнообразия надстроек, я пойман в ловушку старой реализации?

С другой стороны, если я предоставляю необработанные указатели или ссылки из интерфейса, могу ли я рисковать тем, что кто-то удалит память из-под shared_ptr? Или я рискую удалить shared_ptr и сделать мою ссылку недействительной?


См. Мой новый вопрос для примера, связанного с этим.

Ответы [ 6 ]

3 голосов
/ 08 декабря 2010

Например, все или только некоторые из них в порядке:

Это зависит от того, чего вы пытаетесь достичь. Почему вектор содержит shared_ptr с вместо простого хранения Person с по значению? (А вы рассматривали boost::ptr_vector?)

Вы также должны учитывать, что, возможно, вам действительно следует раздать weak_ptr.

Если позже я захочу изменить реализацию на использование johns_very_own_shared_ptr вместо разнообразия надстроек, я пойман в ловушку старой реализации?

В значительной степени, но это не невозможно исправить. (Я подозреваю, что в C ++ 0x либеральное использование ключевого слова auto облегчит эту задачу, поскольку вам не придется так сильно изменять вызывающий код, даже если он не использует typedef s.) Но тогда зачем вам хотеть сделать это?

С другой стороны, если я предоставляю необработанные указатели или ссылки из интерфейса, могу ли я рисковать тем, что кто-то удалит память из-под shared_ptr?

Да, но это не твоя проблема. Люди могут извлечь необработанный указатель из shared_ptr и delete тоже. Но если вы хотите избежать ненужной небезопасности, не указывайте здесь сырые указатели. Ссылки намного лучше, потому что никто никогда не считает, что они должны delete &reference_received_from_api;. (Я надеюсь, что так и будет , в любом случае ^^ ;;;;)

3 голосов
/ 08 декабря 2010

Я бы ввел typedef и изолировал себя от изменений. Как то так:

typedef std::shared_ptr<Person> PersonPtr;

PersonPtr Employeer::getPresident() const;

Я помещаю typedef как этот в заголовок (только один) вместе с предварительными объявлениями Это позволяет легко изменить, если я когда-либо захочу.

2 голосов
/ 08 декабря 2010

Я не должен давать пользователю необработанные указатели, когда вы используете shared_ptr s.Пользователь может удалить его, что приведет к двойному удалению.

Чтобы скрыть использование boost:shared_ptr, вы можете использовать typedef, чтобы скрыть фактический тип, и использовать вместо этого новый тип.

typedef boost::shared_ptr<Person> Person_sptr;
2 голосов
/ 08 декабря 2010

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

со смертельным исходом.

Итак, раздача ссылок, как правило, в порядке (если код клиента принимает адрес, то это не более ваша вина, чем если бы код клиента принимает адрес * shared_ptr), но необработанные указатели, подумайте сначала.

Приветствия и hth.,

1 голос
/ 08 декабря 2010

Единственная причина для выдачи shared_ptr здесь заключается в том, что время жизни возвращенной ссылки на объект не привязано напрямую к времени жизни его резидентности в векторе.

Если вы хотите, чтобы кто-то имел доступ к Person после того, как он перестал быть Employee, тогда подойдет shared_ptr. Скажем, если вы перемещаете Person в vector для другого Employer.

0 голосов
/ 08 декабря 2010

Я работаю над проектом среднего размера, который связан с несколькими библиотеками.Некоторые из этих библиотек имеют свои собственные подсистемы управления памятью (APR, MFC) и действительно раздражают меня.Независимо от того, является ли их взгляд на мир хорошим или плохим, он полностью отличается от всех остальных и требует немного больше кода, чем в противном случае.

Кроме того, эти библиотеки заменяют malloc или new на jemalloc или сборщик мусора Boehm-Demers-Weiser намного сложнее ( в Windows это уже достаточно сложно ).

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

  1. раздачи необработанных указателей (плюс обещание, котороеуказатели могут быть delete d или Destroy() функцией, которая вызывается для освобождения объектов)
  2. принимает функцию или аргумент, подобный распределителю STL, так что вы можете подключиться к любому пользователюиспользование для управления памятью (не стесняйтесь использовать по умолчанию new и std::allocator)
  3. , чтобы пользователи библиотеки передавали вам выделенные буферы памяти ( как std::vector s )

Использование библиотек такого типа не должно быть неприятным:

// situation (1) from above
std::shared_ptr<Foo> foo(Library_factory::get_Foo(), Library_factory::deallocate);

// situation (2) above (declaration on next line is in a header file)
template<typename allocator=std::allocator<Foo> > Foo* library_function_call();
boost::shared_ptr<Foo> foo = library_function_call();

// situation (3) above, need to fill a buffer of ten objects
std::vector<Foo> foo_buffer(10);
fill_buffer(&foo_buffer[0], foo_buffer.size());
...