Partilhar via


Como criar e usar instâncias unique_ptr

Um unique_ptr não compartilha seu ponteiro. Não pode ser copiado para outro unique_ptr, passado por valor para uma função, nem usado em qualquer algoritmo STL que exija que cópias sejam feitas. Um unique_ptr só pode ser movido. Isso significa que a propriedade do recurso de memória é transferida para outro unique_ptr e que o unique_ptr original não a possui mais. É recomendável que você restrinja um objeto a um proprietário, porque a propriedade múltipla adiciona complexidade à lógica do programa. Portanto, quando você precisa de um ponteiro inteligente para um objeto C++ simples, use unique_ptr, e quando você construir um unique_ptr, use a função auxiliar make_unique.

O diagrama a seguir ilustra a transferência de propriedade entre duas instâncias de unique_ptr.

Movendo a propriedade de um unique_ptr

unique_ptr é definido no cabeçalho <memory> no STL. É exatamente tão eficiente quanto um ponteiro bruto e pode ser usado em contêineres STL. A adição de instâncias de unique_ptr a contêineres STL é eficiente porque o construtor de movimentação do unique_ptr elimina a necessidade da operação de cópia.

Exemplo

O exemplo a seguir mostra como criar instâncias de unique_ptr e passá-las entre as funções.

unique_ptr<Song> SongFactory(const std::wstring& artist, const std::wstring& title)
{
    // Implicit move operation into the variable that stores the result. 
    return make_unique<Song>(artist, title);
}

void MakeSongs()
{
    // Create a new unique_ptr with a new object.
    auto song = make_unique<Song>(L"Mr. Children", L"Namonaki Uta");

    // Use the unique_ptr.
    vector<wstring> titles = { song->title };

    // Move raw pointer from one unique_ptr to another.
    unique_ptr<Song> song2 = std::move(song);

    // Obtain unique_ptr from function that returns by value.
    auto song3 = SongFactory(L"Michael Jackson", L"Beat It");
}

Esses exemplos demonstram esta característica básica de unique_ptr: pode ser movido, mas não copiado. “Mover” transfere a propriedade a um novo unique_ptr e redefine o unique_ptr antigo.

O exemplo a seguir mostra como criar instâncias de unique_ptr e usá-las em um vetor.

void SongVector()
{
    vector<unique_ptr<Song>> songs;

    // Create a few new unique_ptr<Song> instances 
    // and add them to vector using implicit move semantics.
    songs.push_back(make_unique<Song>(L"B'z", L"Juice"));
    songs.push_back(make_unique<Song>(L"Namie Amuro", L"Funky Town"));
    songs.push_back(make_unique<Song>(L"Kome Kome Club", L"Kimi ga Iru Dake de"));
    songs.push_back(make_unique<Song>(L"Ayumi Hamasaki", L"Poker Face"));

    // Pass by const reference when possible to avoid copying. 
    for (const auto& song : songs)
    {
        wcout << L"Artist: " << song->artist << L"   Title: " << song->title << endl; 
    }    
}

No intervalo do loop, observe que unique_ptr é passado por referência. Se você tentar passar por valor aqui, o compilador lançará um erro porque o construtor de cópia unique_ptr foi excluído.

O exemplo a seguir mostra como inicializar um unique_ptr que é membro da classe.

class MyClass
{
private:
    // MyClass owns the unique_ptr.
    unique_ptr<ClassFactory> factory;
public:

    // Initialize by using make_unique with ClassFactory default constructor.
    MyClass() : factory ( make_unique<ClassFactory>())
    {
    }

    void MakeClass()
    {
        factory->DoSomething();
    }
};

Você pode usar make_unique para criar um unique_ptr para uma matriz, mas não pode usar make_unique para inicializar os elementos da matriz.

    // Create a unique_ptr to an array of 5 integers.
    auto p = make_unique<int[]>(5);

    // Initialize the array. 
    for (int i = 0; i < 5; ++i)
    {
        p[i] = i;
        wcout << p[i] << endl;
    }

Para obter mais exemplos, consulte make_unique.

Consulte também

Referência

make_unique

Conceitos

Ponteiros inteligentes (C++ moderno)