2014-10-23 3 views
2

Похоже, что std::unique_ptr решает проблему, которая также может быть решена с помощью семантики перемещения, то есть передачи права собственности на ресурс с уникальным ресурсом. Вот некоторые примеры, когда они, кажется, выполняют ту же работу:Передача единоличного владельца: unique_ptr vs move semantics

class SomeResource { /* resourcey stuff */ }; 

void ProcessResourcePtr(std::unique_ptr<SomeResource> r) { /* do stuff */ } 
void ProcessResourceRvalRef(SomeResource&& r) { /* do stuff */ } 

class OwnerOfResourcePtr { 
private: 
    std::unique_ptr<SomeResource> r_; 
public: 
    OwnerOfResourcePtr(std::unique_ptr<SomeResource> r) : r_(std::move(r)) { } 
}; 

class OwnerOfResourceRvalRef { 
private: 
    SomeResource r_; 
public: 
    OwnerOfResourceRvalRef(SomeResource&& r) : r_(std::move(r)) { } 
}; 


int main() 
{ 
    // transfer ownership to function via unique_ptr 
    std::unique_ptr<SomeResource> r1(new SomeResource()); 
    ProcessResourcePtr(std::move(r1)); 

    // transfer ownership to function via rvalue ref 
    SomeResource r2; 
    ProcessResourceRvalRef(std::move(r2)); 

    // transfer ownership to instance via unique_ptr 
    std::unique_ptr<SomeResource> r3(new SomeResource()); 
    OwnerOfResourcePtr(std::move(r3)); 

    // transfer ownership to instance via rvalue ref 
    SomeResource r4; 
    OwnerOfResourceRvalRef(std::move(r4)); 

    return 0; 
} 

На мой взгляд, это как решить почти точно такая же проблема, по-разному. Я не на 100% понимаю преимущества одного из способов против другого. Я знаю, что перемещение указателя, вероятно, быстрее, чем перемещение конструкторов/назначений, хотя оба они обычно считаются достаточно эффективными. Я также знаю, что семантика перемещения позволяет хранить ваши данные в стеке (см. R2, r4) вместо того, чтобы требовать выделения/освобождения кучи с помощью new/malloc/etc (см. R1, r3), который я считаю хорошим предмет (есть?).

В целом, когда следует предпочесть unique_ptr над семантикой перемещения или наоборот? Существуют ли какие-либо варианты использования, которые могут быть решены только одним или другим?

ответ

3

Если у вас есть класс (возможно, написанный кем-то другим), который не имеет конструктора перемещения, возможно, даже не конструктора копирования, тогда вам, возможно, придется использовать unique_ptr.

Если экземпляр является необязательным, то есть может отсутствовать, вы должны использовать unique_ptr.

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

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

+1

Если экземпляр не является обязательным, вы должны использовать 'std :: experimental :: optional' или' boost :: optional'. Для этого не имеет смысла использовать 'std :: unique_ptr'. Кроме того, я не думаю, что вопрос OP даже имеет смысл. 'std :: unique_ptr' показывает пакет политики собственности, который можно повторно использовать. Похоже, что это сводится к «Когда я должен использовать« std :: unique_ptr »вместо моей собственной политики владения?». – Rapptz

+0

@Rapptz: 'std :: unique_ptr' является частью стандартного C++, который для некоторых людей является отличным преимуществом перед« экспериментальным »или« boost ». Я согласен с тем, что ОП, похоже, ищет оправдание, чтобы избежать «std :: unique_ptr», когда это действительно полезно. –

+0

'std :: experimental :: optional' технически также является частью стандарта. Точно так же, как вещи в TR1 были частью стандарта в то время. Оба clang и gcc поддерживают 'std :: experimental :: optional'. – Rapptz