Как обстоят дела с общим указателем? - PullRequest
0 голосов
/ 16 сентября 2011

Моя программа не работает из-за добавления указателя на вектор. После большого чтения и удаления я изменил его на добавление общего указателя в набор (с помощью вставки), который сначала был в порядке, но теперь тоже не работает. Я пробовал два решения ; ни сработало. Один тоже не удался, а другой, make совместно используемый вид, не компилировался.

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

Ответы [ 3 ]

3 голосов
/ 16 сентября 2011

Все дело в собственности. Считается, что сущность (функция или объект) «владеет» указателем, если это задача этой сущности, чтобы гарантировать, что указатель удален. Каждый раз, когда вы используете new, кто-то, где-то должен стать владельцем возвращаемого указателя. Если это не так, у вас утечка памяти.

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

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

Итак, если у вас есть это:

std::auto_ptr<int> p1 = new int(4);

Это гарантированно будет уничтожено (при условии, что лицо, его удерживающее, должным образом очищено). Когда p1 падает со стека, указатель будет уничтожен. Если p1 был членом класса, указатель будет уничтожен при уничтожении этого экземпляра класса. Время жизни указателя ограничено. Boost фактически имеет не копируемый эквивалент, который называется boost::scoped_ptr.

Есть несколько правил, которые вы должны соблюдать при использовании любых интеллектуальных указателей. Это самое важное.

Правило № 1: Если вы создаете экземпляр умного указателя из голого указателя, то вы говорите: «Ни один объект в настоящее время не владеет этим указателем. Теперь я давая вам право собственности , умный указатель. " Вот что значит построить объект умного указателя из голого указателя.

Этот код является нарушением Правила № 1:

std::auto_ptr<int> p1 = new int(4);
std::auto_ptr<int> p2 = p1.get();

Функция auto_ptr::get() возвращает указатель, так что это допустимый код C ++ (компилируется). Однако и p1, и p2 теперь считают, что они владеют указателем. Потому что auto_ptr только для моделей с одним -обладанием, что недопустимо. Когда p2 уничтожен, он удалит указатель. Затем, когда p1 будет уничтожен, он попытается удалить такой же указатель.

К сожалению.

Теперь, когда мы все ясно понимаем правило № 1, давайте посмотрим на shared_ptr. Этот умный указатель моделирует общих владельцев. Несколько объектов могут одновременно претендовать на владение указателем. Указатель будет удален только после того, как все из них закончат его использование. Таким образом, если все 3 объекта содержат shared_ptr к одному и тому же объекту, этот объект не будет удален, пока не будут удалены все три, которые содержат shared_ptr.

Важно понимать, что shared_ptr - это умный указатель. И, следовательно, оно подпадает под правило № 1.

Это может не иметь смысла. В конце концов, это должно разрешить совместное владение. Это должно означать, что это допустимо, верно?

shared_ptr<int> p1 = new int(4);
shared_ptr<int> p2 = p1.get();

Неа. Это все еще не так. Разница между auto_ptr и shared_ptr заключается в том, что вы можете сделать это с помощью shared_ptr:

shared_ptr<int> p1 = new int(4);
shared_ptr<int> p2 = p1;

Это копия конструкции p2 из p1. Существует принципиальная разница между созданием shared_ptr из голого указателя и созданием из уже существующего shared_ptr. Последнее - то, что фактически разделяет собственность между этими двумя. Первый просто вызовет зло.

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

Существует один полу-бэкдор: enable_shared_from_this. Если вы наследуете класс от этого типа, то у вашего класса будет shared_from_this закрытый член, который функции-члены класса могут использовать для передачи прав собственности. Итак:

struct Type : public enable_shared_from_this
{
  DoSomething()
  {
    shared_ptr<Type> p2 = shared_from_this();
    FunctionThatTakesOwnership(p2);
  }
};

shared_ptr<Type> p1 = new Type;
p1->DoSomething();

Кроме этого, вам придется передать право собственности, явно скопировав объект.

2 голосов
/ 16 сентября 2011

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

Например, классы A1 и A2 должны использовать один и тот же объект типа S. Таким образом, оба должны содержать указатель на S. Но кому принадлежит только этот объект (кто должен его удалить). Допустим, А1. Итак, A1 в своем деструкторе удалит S. Но то, что произойдет, если A1 будет уничтожено до того, как A2 - A2 будет иметь висячий указатель (указатель на удаленный объект) на S. Использование shared_ptr вместо необработанного указателя на S (S *) решает эту проблему.

0 голосов
/ 16 сентября 2011

Общий указатель становится владельцем указанного объекта.

Семантика этого заключается в том, что при копировании shared_ptr каждый по очереди делится дескриптором своих общих знаний о владельце.Когда последняя копия уничтожается, она уничтожает объект.Это избавляет вас от необходимости вручную управлять вызовом на delete в нужное время и (надеюсь) сделать утечки памяти более редкими.

Чтобы это работало, нормальным стилем является выделение кучи newпри создании объекта используйте объект shared_ptr, после чего избегайте непосредственной работы с необработанным указателем.

Вы правильно используете shared_ptr в наборе STL.Это правильный способ гарантировать, что объект очищается при уничтожении набора.

...