Некоторые std :: unique_ptr используют и & quot; gotchas & quot;

Каковы некоторые из C ++ 11 std::unique_ptr использует и подводные камни?

Могу ли я использовать std::unique_ptr также хранить динамически размещенные массивы?

Могу ли я использовать std::unique_ptr также с ресурсами, использующими пользовательский механизм удаления?

7

Решение

Давайте организуем некоторые использования и ошибки, используя Q&Формат.


Q1: Я хотел бы хранить указатель в класс Component внутри моего класса X,
Я не хочу класс «контейнер» X быть копируемым; X является единственным владельцем Component экземпляров.
я знаю это владеющим сырье указатели являются плохой вещью и потенциальными источниками «утечек» (вместо наблюдения сырые указатели в порядке).
Какие умный указатель Могу ли я использовать для этой цели?

A1: C ++ 11-х std::unique_ptr это конечно хороший вариант.

Это хорошо в случаях уникальная (не общая) собственность, и не имеет накладных расходов std::shared_ptr,
Это отличная замена для предыдущего C ++ 98/03 boost::scoped_ptr,
На самом деле, кроме того, std::unique_ptr обеспечивает переместить семантику.
Итак, если класс X содержит unique_ptr<Component> члены данных (и другие подвижные члены данных), весь класс X будет автоматически подвижна.

Пример использования показан ниже:

#include <memory> // for std::unique_ptr

class X
{
std::unique_ptr<Component> m_pComponent;
....

public:
X()
: m_pComponent( new Component() )
{
....
}
}

(Конечно, будучи умный указатель, нет необходимости явно удалять его в деструкторе содержащего класса.)


Q2: Замечательно! Нет необходимости в явном деструкторе, нет std::shared_ptr накладные расходы (типичная философия C ++: «Мы не платим за то, что не используем»), переместить семантику машин уже реализовано!
Однако у меня есть проблема: мой класс Component имеет перегрузку конструктора, которая принимает некоторый параметр, который мне нужно вычислить в коде конструктора перед созданием Component экземпляров. Я пытался использовать обычные operator= Назначение в конструкторе для назначения вновь созданного Component к unique_ptr, но я получил сообщение об ошибке:

X::X()
{
....

const int param = CalculateCoolParameter();

// This assignment fails:
m_pComponent = new Component(param); // <---- Error pointing to '=' here
^--- error
}

A2: ОК, возможно, вы ожидали operator= перегрузка освобождая предыдущее
указатель (если есть) и присвоение вновь созданному.
К сожалению, такой перегрузки нет.
Тем не менее std::unique_ptr::reset() метод подойдет!

m_pComponent.reset( new Component(param) );

Q3: Привет! это unique_ptr это действительно круто!
Мне нравится тот факт, что он умный, он автоматически перемещается и не приносит лишних затрат.
Итак, я хотел бы использовать его для хранения динамически распределяемый массив некоторого постоянного размера (рассчитывается во время выполнения) вместо использования std::vector (в этой части кода я сильно ограничен и не хочу платить за std:vector накладные расходы, так как я не хочу все std::vector динамическое изменение размеров, глубокое копирование и т. д.).

Я попробовал что-то вроде этого:

const size_t count = GetComponentsCount();
unique_ptr<Component> components( new Component[count] );

Компилируется нормально, но я заметил, что ~Component деструктор называется только один раз, вместо этого я ожидал count деструктор звонит! Что здесь не так?

A3: Проблема в том, что с приведенным выше синтаксисом std::unique_ptr использования delete освободить выделенные объекты. Но так как те были распределены с использованием new[], правильный вызов очистки delete[] (не простой delete без скобок).

Чтобы исправить это и проинструктировать unique_ptr правильно использовать delete[] для освобождения ресурсов должен использоваться следующий синтаксис:

unique_ptr<Component[]> components( new Components[count] );
//                  ^^
//
// Note brackets "[]" after the first occurrence of "Component"// in unique_ptr template argument.
//

Q4: Замечательно! Но могу ли я использовать unique_ptr также в тех случаях, когда код выпуска ресурса не выполняется с использованием обычного C ++ delete (или же delete[]), но вместо этого, используя некоторые пользовательская функция очистки, лайк fclose() для C <stdio.h> файлы (открываются с fopen()), или же CloseHandle() для файла Win32 HANDLEs (создано с использованием CreateFile())?

A4: Это определенно возможно: вы можете указать пользовательский удалитель за std::unique_ptr,

например.:

//
// Custom deleter function for FILE*: fclose().
//
std::unique_ptr<FILE,          // <-- the wrapped raw pointer type: FILE*
int(*)(FILE*)> // <-- the custom deleter type: fclose() prototype
myFile( fopen("myfile", "rb"), // <-- resource (FILE*) is returned by fopen()
fclose );              // <-- the deleter function: fclose()//
// Custom deleter functor for Win32 HANDLE: calls CloseHandle().
//
struct CloseHandleDeleter
{
// The following pointer typedef is required, since
// the raw resource is HANDLE (not HANDLE*).
typedef HANDLE pointer;

// Custom deleter: calls CloseHandle().
void operator()(HANDLE handle) const
{
CloseHandle(handle);
}
};

std::unique_ptr<HANDLE, CloseHandleDeleter> myFile( CreateFile(....) );
18

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

Других решений пока нет …

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