Світ, в якому живе Б'ярн, дуже ... академічний, заради кращого терміну. Якщо ваш код може бути розроблений і структурований таким чином, що об’єкти мають дуже навмисні реляційні ієрархії, такі, що відносини власності є жорсткими і непорушними, код перетікає в одну сторону (від високого до низького рівня), а об'єкти розмовляють лише з тими, хто нижче ієрархія, тоді ви не знайдете великої потреби shared_ptr
. Це те, що ви використовуєте в тих рідкісних випадках, коли хтось повинен порушувати правила. Але в іншому випадку ви можете просто вставити все в vector
s або інші структури даних, що використовують значення семантики, і unique_ptr
s для речей, які вам потрібно виділити поодинці.
Хоча це чудовий світ, в якому потрібно жити, це не те, що ти маєш робити весь час. Якщо ви не можете впорядкувати свій код таким чином, оскільки дизайн системи, яку ви намагаєтеся зробити, означає, що це неможливо (або просто глибоко неприємно), то вам доведеться все більше потребувати спільного володіння об'єктами. .
У такій системі проведення голих покажчиків - це не небезпечно точно, але це викликає питання. Найкраще в shared_ptr
тому, що він забезпечує розумні синтаксичні гарантії щодо терміну експлуатації об'єкта. Чи можна її зламати? Звичайно. Але люди також можуть const_cast
щось робити; Основний догляд та годування shared_ptr
повинні забезпечувати розумну якість життя виділених об’єктів, права власності яких повинні бути спільними.
Потім є weak_ptr
s, які неможливо використати за відсутності a shared_ptr
. Якщо ваша система жорстко структурована, ви можете зберігати голий вказівник на якийсь об’єкт, впевнений у тому, що структура програми гарантує, що об’єкт, на який вказували, пережив вас. Ви можете викликати функцію, яка повертає вказівник на якесь внутрішнє або зовнішнє значення (наприклад, знайдіть об'єкт з назвою X). У правильно структурованому коді ця функція буде доступна вам лише у тому випадку, якщо тривалість життя об'єкта гарантовано перевищить вашу власну; таким чином, зберігати цей голий вказівник у вашому об’єкті добре.
Оскільки цієї жорсткості не завжди вдається досягти в реальних системах, вам потрібен певний спосіб розумного забезпечення терміну експлуатації. Іноді вам не потрібно повного права власності; іноді просто потрібно вміти знати, коли вказівник поганий чи хороший. Ось де це weak_ptr
входить. Були випадки, коли я міг би використовувати unique_ptr
або boost::scoped_ptr
, але мені довелося скористатись тим, shared_ptr
що мені спеціально потрібно було дати комусь "мінливий" покажчик. Вказівник, який термін життя був невизначений, і вони могли запитувати, коли цей покажчик був знищений.
Безпечний спосіб вижити, коли стан світу невизначений.
Могло це зробити якийсь виклик функції, щоб отримати вказівник, а не через weak_ptr
? Так, але це можна було легше зламати. Функція, яка повертає голий покажчик, не може синтаксично запропонувати користувачеві робити щось на зразок зберігати цей покажчик довгостроково. Повернення shared_ptr
також робить його занадто простим для того, щоб хтось просто зберігав його і потенційно продовжував тривалість життя предмета. weak_ptr
Однак повернення настійно говорить про те, що зберігання отриманого shared_ptr
вами lock
- це ... сумнівна ідея. Це не завадить вам зробити це, але нічого в C ++ не заважає вам порушити код. weak_ptr
забезпечує деякий мінімальний опір від природної речі.
Тепер це не означає, що shared_ptr
не можна перестаратися ; це, звичайно, може. Особливо до- unique_ptr
, було багато випадків, коли я просто використовував, boost::shared_ptr
тому що мені потрібно було передати вказівник RAII навколо або внести його до списку. Без рухомої семантики і unique_ptr
, boost::shared_ptr
було єдиним реальним рішенням.
І використовувати його можна в місцях, де це зовсім непотрібно. Як було сказано вище, правильна структура коду може усунути потребу в деяких використання shared_ptr
. Але якщо ваша система не може бути структурована як така і все-таки робити все, що їй потрібно, shared_ptr
буде корисною.