Враховуючи декілька редагувань, у мене складається враження, що вичерпне резюме було б корисним.
1. Коли не потрібно
Є дві ситуації, коли не слід використовувати розумні вказівники.
Перший - це абсолютно та сама ситуація, коли C++насправді не слід використовувати клас. IE: Межа DLL, якщо ви не пропонуєте вихідний код клієнту. Скажімо анекдотично.
Друге трапляється набагато частіше: розумний менеджер означає власність . Ви можете використовувати вказівники для вказівки на існуючі ресурси, не керуючи їхнім життям, наприклад:
void notowner(const std::string& name)
{
Class* pointer(0);
if (name == "cat")
pointer = getCat();
else if (name == "dog")
pointer = getDog();
if (pointer) doSomething(*pointer);
}
Цей приклад обмежений. Але покажчик семантично відрізняється від посилання тим, що може вказувати на недійсне розташування (нульовий покажчик). У цьому випадку цілком нормально не використовувати замість цього розумний вказівник, оскільки ви не хочете керувати життям об’єкта.
2. Розумні менеджери
Якщо ви не пишете клас розумного менеджера, якщо ви використовуєте ключове слово, delete ви робите щось не так.
Це суперечлива точка зору, але, переглянувши стільки прикладів недосконалого коду, я більше не ризикую. Отже, якщо ви пишете, newвам потрібен розумний менеджер для нещодавно виділеної пам’яті. І це вам потрібно прямо зараз.
Це не означає, що ви менше програміст! Навпаки, повторне використання коду, який, як було доведено, працює замість того, щоб знову і знову винаходити колесо, є ключовою навичкою.
Тепер справжня складність починається: який розумний менеджер?
3. Розумні покажчики
Звідти є різні розумні вказівники з різними характеристиками.
Пропуску, std::auto_ptrякого зазвичай слід уникати (його семантична копія вкручена).
scoped_ptr: немає накладних витрат, не можна скопіювати або перемістити.
unique_ptr: немає накладних витрат, не можна скопіювати, можна перемістити.
shared_ptr/ weak_ptr: деякі накладні витрати (підрахунок посилань), можна скопіювати.
Зазвичай намагаються використовувати або scoped_ptrабо unique_ptr. Якщо вам потрібно кілька власників, спробуйте змінити дизайн. Якщо ви не можете змінити дизайн і вам дійсно потрібні кілька власників, використовуйте a shared_ptr, але остерігайтеся циклів посилань, які слід порушити, використовуючи weak_ptrдесь посередині.
4. Розумні контейнери
Багато розумні вказівники не призначені для копіювання, тому їх використання з контейнерами STL дещо скомпрометовано.
Замість того, щоб вдаватися до shared_ptrта його накладних витрат, використовуйте розумні контейнери з контейнера Boost Pointer . Вони імітують інтерфейс класичних контейнерів STL, але зберігають власні вказівники.
5. Прокат свого
Бувають ситуації, коли вам може знадобитися створити власного розумного менеджера. Переконайтеся, що заздалегідь ви не пропустили якусь функцію в бібліотеках, якими ви користуєтесь.
Написати розумного менеджера за наявності винятків досить складно. Зазвичай ви не можете припустити, що пам’ять доступна ( newможе вийти з ладу) або що вона Copy Constructorмає no throwгарантію.
Може бути прийнятним, дещо, ігнорувати std::bad_allocвиняток і нав'язувати, що Copy Constructors ряду помічників не виходять з ладу ... зрештою, це те, що boost::shared_ptrробить Dпараметр шаблону видалення .
Але я б не рекомендував це, особливо для початківців. Це складне питання, і ви навряд чи зараз помітите помилки.
6. Приклади
using namespace boost;
struct Cloneable
{
virtual ~Cloneable() {}
virtual Cloneable* clone() const = 0;
};
struct Derived: Cloneable
{
virtual Derived* clone() const { new Derived(*this); }
};
void scoped()
{
scoped_ptr<Cloneable> c(new Derived);
}
unique_ptr<Cloneable> unique()
{
return unique_ptr<Cloneable>(new Derived);
}
void shared()
{
shared_ptr<Cloneable> n1(new Derived);
weak_ptr<Cloneable> w = n1;
{
shared_ptr<Cloneable> n2 = n1;
n1.reset();
assert(n1.get() == 0);
assert(n2.get() != 0);
assert(!w.expired() && w.get() != 0);
}
assert(w.expired());
}
void container()
{
ptr_vector<Cloneable> vec;
vec.push_back(new Derived);
vec.push_back(new Derived);
vec.push_back(
vec.front().clone()
);
}