2015-02-13 6 views
2

С std::unique_ptr::reset вы можете легко вернуть свой экземпляр в новое состояние.std :: unique_ptr и reset() или метод Reset для вашего класса?

Pre-C++ 11, для достижения аналогичного поведения, я видел, что многие классы определяют метод Reset(), который сбрасывает все его внутренние члены. Но теперь я думаю, что то же самое можно было бы сделать с помощью только конструктора и деструктора и reset в unique_ptr для нового экземпляра класса. Есть ли какие-то преимущества, которые мне не хватает, почему вы все равно предпочтете метод Reset(), или мы всегда должны просто использовать unique_ptr и reset его новому экземпляру всякий раз, когда мы хотим «перезагрузить» наш класс?

Единственное, что я могу придумать, это то, что вы сохраняете выделение/удаление, которое иногда может быть дорогостоящим. Стоимость курса - это сложность сохранения функции Reset() и обеспечение ее актуальности при других изменениях кода.

Это он? Это вопрос сложности с производительностью?

+1

Что делать, если вы хотите выделить свой объект в стеке? – Brian

ответ

0

Единственное преимущество я могу думать о том, что вы сохраняете выделения/удаления, которые иногда могут быть дорогими

не только распределение, что может быть дорогими, но и возможно фрагментации памяти, плохо местность (благодаря @Cris для сроков, которые искали в моем сознании), во время частых сбрасываний, в конечном итоге приведет к огромным проблемам с производительностью.

unique_ptr не предназначен для сброса вашего состояния экземпляра. unique_ptr::reset сбрасывает unique_ptr, что составляет В результате вызов деструктора на «старый» экземпляр.

Так что это полностью отличается от вашего экземпляра Reset метода.

В случае сброса

  • не экземпляр новой памяти -> про

  • потенциально могут повторно использовать ту же память, не громя его, так держать ваши данные выровнены и плотно упакованы (зависит от того, как вы implment вашего метода Reset) -> про

  • не безопасное управление памятью, что приводит к MEM утечек -> минусы

В случае unique_ptr

  • нет указателя наложения спектров и управление памятью управления -> про
  • выделение нового экземпляра каждый раз -> против

Все профи и минус, естественно, можно утверждать, зависит от конкретной реализации и фактических требований.

0

Распределение/исключение является одной из затрат, но также существует стоимость дополнительного уровня косвенности для доступа к объекту с помощью указателя. Например, более низкая локальность данных.

Функция Reset() также может быть вызвана в контекстах, где у вас есть только ссылка или указатель. Единственный объект, который должен знать, что объект управляется unique_ptr, является владельцем. В других контекстах лучше использовать ссылку или указатель.

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

Конечно, это не ново в C++ 11, это всегда можно было сделать с помощью выделенных кучей объектов. Это всего лишь один пример того, как unique_ptr облегчает жизнь.

0

Думаю, вы смешиваете вещи здесь.

unique_ptrshared_ptr - это конструкция для представления собственности. Использование unique_ptr означает, что ваши классы не могут быть скопированы или скопированы, если вы не предоставите конструктор копирования и оператор назначения копирования самостоятельно. Это была бы дополнительная работа.

Так что, если вы все еще хотите, чтобы обеспечить способ сброса, но не хотите, чтобы рука код сброса каждой переменной члена вы могли бы сделать что-то вроде этого:

MyClass::Reset() 
{ 
    this->~MyClass(); 
    new(this) MyClass(); 
} 

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

Недостатки такого подхода

  • Не сохранить исключение, поэтому, если ваш конструктор может бросить вас будут проблемы.
  • Динамическая память, которую ваши члены используют внутри, выбрасывается и не используется повторно. Например, член vector и связанная с ним память в куче освобождаются вместо повторного использования.

На самом деле вы можете также реализовать Reset как

MyClass::Reset() 
{ 
    *this = MyClass(); 
} 

, хотя это может быть медленнее, чем предыдущее решение.

4

Вот это действительно хороший общий способ сбросить состояние вашего класса его по умолчанию сконструированной состояние:

// Previously constructed MyClass myvalue = ... 
myvalue = MyClass{}; 

Это включает в себя две операции:

  1. По умолчанию строительства.
  2. Переместить назначение.

В идеале, оба из них должны быть дешевыми.

+0

Три операции ?: 1. Строительство по умолчанию. 2. Уничтожение 'myvalue'. 3. Переместить назначение. – NHDaly

+0

Не могли бы мы как-то пропустить назначение перемещения и заставить компилятор просто уничтожить и построить класс на месте? Я бы никогда не написал это, но что-то вроде 'MyClass :: ~ MyClass (& myvalue); new (& myvalue) MyClass; ' – NHDaly