Відповіді:
Якщо у вас є властивості, ви можете призначити кожному розумному вказівнику. Є три важливі властивості.
Перший означає, що розумний вказівник не може видалити об'єкт, оскільки він не володіє ним. Другий означає, що лише один розумний вказівник може одночасно вказувати на один і той же об’єкт. Якщо розумний покажчик повинен повернутися з функцій, право власності передається, наприклад, поверненому розумному вказівнику.
Третя означає, що кілька розумних покажчиків можуть вказувати на один і той же об'єкт одночасно. Це стосується і необробленого вказівника , однак у сирої вказівки відсутня важлива особливість: вони не визначають, володіють вони чи ні. Частка власного вказівника власності видалить об'єкт, якщо кожен власник відмовиться від об'єкта. Така поведінка часто потрібна, тому спільне володіння розумними покажчиками широко поширене.
Деякі, що володіють розумними покажчиками, не підтримують ні другого, ні третього. Тому їх не можна повернути з функцій або передати десь в іншому місці. Що найбільше підходить для RAII
цілей, коли розумний вказівник зберігається на локальному рівні та просто створюється, тому він звільняє об'єкт після того, як він виходить із сфери застосування.
Частка власності може бути реалізована за допомогою конструктора копій. Це природно копіює інтелектуальний покажчик, і копія, і оригінал посилаються на один і той же об'єкт. Передача права власності реально не може бути реалізована в C ++, оскільки немає засобів для передачі чого-небудь з одного об'єкта на інший, підтримуваний мовою: Якщо ви намагаєтесь повернути об'єкт з функції, то відбувається те, що об'єкт скопіюється. Отже, розумний покажчик, який реалізує передачу права власності, повинен використовувати конструктор копій для здійснення цієї передачі права власності. Однак це, в свою чергу, порушує його використання в контейнерах, оскільки вимоги констатують певну поведінку конструктора копіювання елементів контейнерів, несумісного з цим так званим "рухомим конструктором" поведінкою цих розумних покажчиків.
C ++ 1x забезпечує вбудовану підтримку передачі права власності шляхом введення так званих "конструкторів переміщення" та "операторів присвоєння переміщення". Він також постачається з таким розумним вказівником про передачу власності, який називається unique_ptr
.
scoped_ptr
- розумний покажчик, який не є ні передавальним, ні спільним. Це просто корисно, якщо вам потрібно локально виділити пам'ять, але будьте впевнені, вона знову звільниться, коли вона вийде за межі сфери. Але це все одно можна замінити іншим scoped_ptr, якщо ви хочете зробити це.
shared_ptr
- розумний покажчик, який розділяє право власності (третій вид вище). Він посилається на підрахунок, щоб він міг бачити, коли остання його копія виходить за межі, а потім звільняє керований об'єкт.
weak_ptr
- розумний вказівник, який не є власником. Він використовується для посилання на керований об'єкт (керований shared_ptr) без додавання довідкового рахунку. Як правило, вам потрібно буде дістати необроблений покажчик з shared_ptr і скопіювати це навколо. Але це було б не безпечно, так як у вас не було б способу перевірити, коли об’єкт було фактично видалено. Отже, слабкий_птр забезпечує засоби шляхом посилання на об’єкт, яким керує спільний_птр. Якщо вам потрібно отримати доступ до об’єкта, ви можете заблокувати управління ним (щоб уникнути того, що в іншому потоці спільний_ptr звільняє його під час використання об'єкта), а потім використовувати його. Якщо слабкий_птр вказує на вже видалений об’єкт, він помітить вас, кинувши виняток. Використання слабкого_птр є найбільш вигідним, коли у вас є циклічна довідка: Підрахунок посилань не може легко впоратися з такою ситуацією.
intrusive_ptr
подібний до shared_ptr, але він не зберігає кількість посилань у shared_ptr, але залишає збільшуючи / зменшуючи кількість до деяких допоміжних функцій, які повинні бути визначені об'єктом, яким керується. Це має ту перевагу, що вже посилається об'єкт (у якого кількість посилань збільшується за допомогою механізму підрахунку зовнішніх посилань) може бути заповнений в intrusive_ptr - тому що кількість посилань більше не є внутрішньою для інтелектуального вказівника, але розумний вказівник використовує існуючий механізм відліку опор.
unique_ptr
- це передача покажчика власності. Ви не можете скопіювати його, але ви можете перемістити його за допомогою конструкторів переміщення C ++ 1x:
unique_ptr<type> p(new type);
unique_ptr<type> q(p); // not legal!
unique_ptr<type> r(move(p)); // legal. p is now empty, but r owns the object
unique_ptr<type> s(function_returning_a_unique_ptr()); // legal!
Це семантичне значення, яке підпорядковує std :: auto_ptr, але через відсутність нашої підтримки для переміщення, він не може забезпечити їх без підводних каменів. unique_ptr автоматично вкраде ресурси з тимчасового іншого унікального_ptr, що є однією з ключових особливостей семантики переміщення. auto_ptr буде застарілим у наступному випуску C ++ Standard на користь унікального_ptr. C ++ 1x також дозволить набивати в контейнери об'єкти, які є лише рухомими, але не підлягають копіюванню. Таким чином, ви можете вкласти, наприклад, унікальні_ptr у вектор. Я зупинюсь тут і посилаюсь на точну статтю про це, якщо ви хочете прочитати більше про це.
auto_ptr
вже застаріла (C ++ 11).
intrusive_ptr
може бути кращим shared_ptr
для кращої узгодженості кешу. Мабуть, кеш працює краще, якщо ви зберігаєте підрахунок посилань як частину пам'яті самого керованого об'єкта замість окремого об'єкта. Це може бути реалізовано в шаблоні або надкласі керованого об'єкта.
scoped_ptr - найпростіший. Коли він виходить за межі, він руйнується. Наступний код незаконний (scoped_ptrs не підлягає копіюванню), але він ілюструє точку:
std::vector< scoped_ptr<T> > tPtrVec;
{
scoped_ptr<T> tPtr(new T());
tPtrVec.push_back(tPtr);
// raw T* is freed
}
tPtrVec[0]->DoSomething(); // accessing freed memory
shared_ptr вважається посиланням. Кожен раз, коли відбувається копія або призначення, кількість посилань збільшується. Кожен раз, коли деструктор екземпляра спрацьовує, кількість опорних T * зменшується. Як тільки вона дорівнює 0, вказівник звільняється.
std::vector< shared_ptr<T> > tPtrVec;
{
shared_ptr<T> tPtr(new T());
// This copy to tPtrVec.push_back and ultimately to the vector storage
// causes the reference count to go from 1->2
tPtrVec.push_back(tPtr);
// num references to T goes from 2->1 on the destruction of tPtr
}
tPtrVec[0]->DoSomething(); // raw T* still exists, so this is safe
weak_ptr слабка посилання на загальний покажчик , який вимагає від вас , щоб перевірити, якщо загострений до shared_ptr ще навколо
std::vector< weak_ptr<T> > tPtrVec;
{
shared_ptr<T> tPtr(new T());
tPtrVec.push_back(tPtr);
// num references to T goes from 1->0
}
shared_ptr<T> tPtrAccessed = tPtrVec[0].lock();
if (tPtrAccessed[0].get() == 0)
{
cout << "Raw T* was freed, can't access it"
}
else
{
tPtrVec[0]->DoSomething(); // raw
}
intrusive_ptr зазвичай використовується, коли є сторонній інтелектуальний ptr, який ви повинні використовувати. Він запустить безкоштовну функцію для додавання та зменшення кількості посилань. Перегляньте посилання для збільшення документації для отримання додаткової інформації.
if (tPtrAccessed[0].get() == 0)
припустимо бути if (tPtrAccessed.get() == 0)
?
Не забувайте boost::ptr_container
в жодному опитуванні підвищення розумних покажчиків. Вони можуть бути безцінними в ситуаціях, коли напр. std::vector<boost::shared_ptr<T> >
, Буде занадто повільно.
Другу пораду щодо перегляду документації. Це не так страшно, як здається. І кілька коротких підказок:
scoped_ptr
- покажчик автоматично видаляється, коли він виходить за межі області. Примітка - призначення не можливе, але не вносить накладних витратintrusive_ptr
- посилання підрахунку посилань без накладних витрат smart_ptr
. Однак сам об'єкт зберігає довідкову кількістьweak_ptr
- працює разом із shared_ptr
вирішенням ситуацій, що призводять до кругових залежностей (читайте документацію та шукайте в Google для отримання приємної картини;)shared_ptr
- загальні, найпотужніші (і важкі) розумних покажчиків (з тих, які пропонує boost)auto_ptr
, що забезпечує об'єкт, на який він вказує, автоматично знищується, коли контроль залишає область. Однак він відрізняється семантикою копіювання, ніж решта хлопців.unique_ptr
- поставляється із C ++ 0xВідповідь на редагування: Так