Я пытаюсь понять, как это std::unique_ptr
работает, и для этого я нашел этот документ. Автор исходит из следующего примера:
#include <utility> //declarations of unique_ptr
using std::unique_ptr;
// default construction
unique_ptr<int> up; //creates an empty object
// initialize with an argument
unique_ptr<int> uptr (new int(3));
double *pd= new double;
unique_ptr<double> uptr2 (pd);
// overloaded * and ->
*uptr2 = 23.5;
unique_ptr<std::string> ups (new std::string("hello"));
int len=ups->size();
Меня смущает то, что в этой строке
unique_ptr<int> uptr (new int(3));
Мы используем целое число в качестве аргумента (в круглых скобках), и здесь
unique_ptr<double> uptr2 (pd);
мы использовали указатель в качестве аргумента. Какая разница?
Мне также непонятно, чем указатели, объявленные таким образом, будут отличаться от указателей, объявленных "обычным" способом.
c++
pointers
std
unique-ptr
Римский
источник
источник
new int(3)
возвращает указатель на новоеint
, точно так же, какpd
был указатель на новоеdouble
.Ответы:
Конструктор
unique_ptr<T>
принимает необработанный указатель на объект типаT
(поэтому он принимает aT*
).В первом примере:
unique_ptr<int> uptr (new int(3));
Указатель является результатом
new
выражения, а во втором примере:unique_ptr<double> uptr2 (pd);
Указатель сохраняется в
pd
переменной.Концептуально ничего не меняется (вы создаете a
unique_ptr
из необработанного указателя), но второй подход потенциально более опасен, поскольку он позволяет вам, например, делать:unique_ptr<double> uptr2 (pd); // ... unique_ptr<double> uptr3 (pd);
Таким образом, имеется два уникальных указателя, которые эффективно инкапсулируют один и тот же объект (тем самым нарушая семантику уникального указателя).
Вот почему первая форма для создания уникального указателя лучше, когда это возможно. Обратите внимание, что в C ++ 14 мы сможем:
unique_ptr<int> p = make_unique<int>(42);
Что и понятнее, и безопаснее. Теперь по поводу вашего сомнения:
Умные указатели должны моделировать владение объектом и автоматически заботиться об уничтожении указанного объекта, когда последний (умный, владеющий) указатель на этот объект выпадает из области видимости.
Таким образом, вам не нужно запоминать действия
delete
с объектами, размещенными динамически - деструктор интеллектуального указателя сделает это за вас - и не беспокоиться о том, не разыменовать ли (висящий) указатель на объект, который уже был уничтожен:{ unique_ptr<int> p = make_unique<int>(42); // Going out of scope... } // I did not leak my integer here! The destructor of unique_ptr called delete
Теперь
unique_ptr
это умный указатель, который моделирует уникальное владение, что означает, что в любой момент в вашей программе должен быть только один (владеющий) указатель на указанный объект - поэтомуunique_ptr
его нельзя копировать.Если вы используете интеллектуальные указатели таким образом, чтобы не нарушать неявный контракт, который они требуют от вас соблюдать, у вас будет гарантия, что утечка памяти не произойдет, и будет применяться правильная политика владения вашим объектом. Необработанные указатели не дают вам этой гарантии.
источник
model object ownership
,integer leak
в коде илиenforcing ownership policy for object
. Не могли бы вы предложить темы / ресурсы для изучения этих концепций?unique_ptr
, не получив сообщения об ошибке:,The text ">" is unexpected. It may be that this token was intended as a template argument list terminator but the name is not known to be a template.
хотя у меня есть#include <utility>
и#include <memory>
. Любой совет?Нет никакой разницы в работе в обеих концепциях присвоения unique_ptr.
int* intPtr = new int(3); unique_ptr<int> uptr (intPtr);
похож на
unique_ptr<int> uptr (new int(3));
Здесь unique_ptr автоматически удаляет пространство, занимаемое
uptr
.Если вы создаете целое число в пространстве кучи (используя ключевое слово new или malloc ), вам придется очистить эту память самостоятельно (используя соответственно delete или free ).
В приведенном ниже коде
int* heapInt = new int(5);//initialize int in heap memory . .//use heapInt . delete heapInt;
Здесь вам нужно будет удалить heapInt, когда это будет сделано с помощью. Если его не удалить, то происходит утечка памяти.
Для того , чтобы избежать таких утечек памяти unique_ptr используется, где unique_ptr автоматически удаляет пространство , занимаемое heapInt , когда он выходит из области видимости. Таким образом, вам не нужно удалять или освобождать unique_ptr.
источник
Уникальные указатели гарантированно уничтожат объект, которым они управляют, когда они выходят за пределы области видимости. http://en.cppreference.com/w/cpp/memory/unique_ptr
В этом случае:
unique_ptr<double> uptr2 (pd);
pd
будет уничтожен, когдаuptr2
выйдет за рамки. Это облегчает управление памятью за счет автоматического удаления.Случай
unique_ptr<int> uptr (new int(3));
не отличается, за исключением того, что необработанный указатель здесь не присваивается никакой переменной.источник
Из cppreference одним из
std::unique_ptr
конструкторов являетсяявный unique_ptr (указатель p) noexcept;
Итак, чтобы создать новый объект,
std::unique_ptr
нужно передать указатель на его конструктор.unique_ptr<int> uptr (new int(3));
Или это то же самое, что
int *int_ptr = new int(3); std::unique_ptr<int> uptr (int_ptr);
Другое дело, что вам не нужно убирать после его использования. Если вы не используете
std::unique_ptr
(умный указатель), вам придется удалить его вот такdelete int_ptr;
когда он вам больше не нужен, или это вызовет утечку памяти.
источник