Умные указатели семантики владения и равенства

У меня есть пара вопросов для умных указателей, которые раньше я им не давал.

  1. Что значит владеть объектом, указывать на объект и управлять объектом в мире умных указателей? Ранее я думал, что тот, кто владеет объектом, также указывает на него и управляет объектом. Теперь я знаю, что умный указатель может владеть объектом, но указывать на другой объект (псевдонимы-конструкторы). Здесь я нашел действительно хорошее объяснение того, что значит владеть объектом -> http://www.umich.edu/~eecs381/handouts/C++11_smart_ptrs.pdf , но все же я не могу сделать разницу между этими 3 терминами.
  2. Если указатель владеет объектом, но указывает на другой объект, каким объектом он управляет? Тот, кому он принадлежит, или тот, на кого он указывает, или оба? Какой смысл владеть объектом, а не указывать на него?
  3. Когда два умных указателя равны? Могут ли два указателя иметь один и тот же объект и быть разными в одно и то же время? Меня интересует не равенство их ценностей, а вопрос о собственности.
  4. Почему важен порядок владения (помимо использования указателей в качестве ключей в контейнерах)? Я думаю, что это актуально только для shared_ptr.

Все началось с попытки понять owner_before, теперь я более запутался, чем раньше, я начал изучать эту тему .. 🙁

0

Решение

Я думаю, что все ваше замешательство исходит от «конструктора псевдонимов»:

template <typename U>
shared_ptr(const shared_ptr<U>& x, element_type* p)

Какая польза от этой вещи? Ну, он редко используется, но он «разделяет» право собственности на некоторый объект x но когда вы разыграете его, вы получите p вместо. Это все. Никогда не удалит p или сделать что-нибудь еще с этим.

Это может быть полезно, если у вас есть что-то вроде этого:

struct Foo {
Bar bar;
};

struct Baz {
Baz(shared_ptr<Bar> bar) : m_bar(bar) {}
shared_ptr<Bar> m_bar;
};

int main()
{
auto foo = make_shared<Foo>();
Baz baz(shared_ptr<Bar>(foo, &foo.bar));
}

Сейчас baz получает управлять временем жизни foo не зная, что это делает — он заботится только о том, что он управляет временем жизни Bar, но так как наши bar это часть fooмы не можем уничтожить foo без разрушения bar, поэтому мы используем конструктор псевдонимов.

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

1

Другие решения

Старый «сырой» указатель:

someType* pR = new someType(param1, param2); //pR is a pointer
MyOwner.TakeOwnershipOf(pR); // Now MyOwner is the owner, **the one who ONLY should call 'delete pR;'**

Умный указатель:

std::shared_ptr<someType> sp = std::make_shared<someType>(param1, param2);

«Зр» теперь владелец (в коде нет «pR», но внутренне это так). И вам не нужно называть «удалить pR». Это объект, который внутренне хранит указатель на pR и удаляет его, когда он больше не нужен.

sp это объект. «sp-> any» точно так же, как «pR-> any». Это может сбить вас с толку о том, что sp также является указателем. Нет, бывает, что «->» перегружен.

Больше перегружено:

sp.get() такой же как pR, *sp такой же как *pR

sp1 == sp2 такой же как pR1 == pR2 и так же, как sp1.get()==sp2.get()

Хорошая вещь О shared_ptr, например, когда вам нужно хранить один и тот же указатель в нескольких контейнерах. Если какой-либо контейнер удален, сохраненный указатель (sp, которому принадлежит pR) также должен быть удален. Это сделает недействительным указатель, хранящийся в другом контейнере. Вместо проверки других контейнеров на предмет наличия этого указателя, shared_ptr берет на себя ответственность за него. Это вы можете безопасно удалить sp так как pR будет удален только последним контейнером, который хранит sp,

0

Владение

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

Мы можем сказать любой объект p владеет q если существование p гарантирует существование q (желательно без утечек памяти).
Простой случай — прямое владение, где освобождение p также освободит qнапример, если q является членом p, или же q явно освобожден с delete в pдеструктор.
Умные указатели делают это очевидным для людей. Если q хранится в std::unique_ptr член p, мы знаем это p владеет q, Вам не нужно искать (возможно, отсутствует или дублируется) оператор удаления.

Собственность также является переходной, если p владеет q а также q владеет r, затем p должен владеть r,

Aliasing

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

Это то, что делает конструктор псевдонимов для std :: shared_ptr (продемонстрировано в ответе Джона).

Расширяется qпродлить pвремя жизни, поэтому у нас есть указатель на q который на самом деле владеет p, Мы утверждаем компилятору, что p на самом деле владеет qтак что общий птр транзитивно владеет q,

Если p не владеет q, тогда ваша программа скомпилируется, но она не работает, как если бы вы вручную вызывали delete дважды.

Сравнения

Для интеллектуальных указателей stl сравнения передаются в необработанный указатель. Таким образом, умные указатели равны, если они обращаются к одному и тому же объекту, а сравнения касаются места в памяти. Не существует каких-либо определенных поведений, определяющих области памяти, поэтому вы не можете использовать его для чего-то другого, кроме хранения в map или же set,

0
По вопросам рекламы [email protected]