Como criar e usar instâncias shared_ptr
O tipo de shared_ptr é um ponteiro inteligente na biblioteca padrão do C++ que é criada para cenários em que mais de um proprietário pode precisar gerenciar o tempo de vida do objeto na memória. Depois que você inicialize shared_ptr que você pode copiar o, passa pelo valor nos argumentos da função, e atribuí-lo a outras instâncias de shared_ptr . Qualquer ponto das instâncias no mesmo objeto, e compartilha o acesso a um “bloco de controle” que incrementos e reduz que a contagem de referência sempre que shared_ptr novo é adicionado, sai do escopo, ou é redefinido. Quando a contagem de referência chegar a zero, o bloco de controle exclui o recurso e próprio de memória.
A ilustração a seguir mostra várias instâncias de shared_ptr que aponte para um local de memória.
Exemplo
Sempre que possível, use a função de make_shared (<memory>) para criar shared_ptr quando o recurso de memória é criado pela primeira vez. make_shared exceções gerais é seguro. Usa a mesma chamada para alocar memória para o bloco de controle e o recurso dessa maneira, e reduz a sobrecarga de compilação. Se você não usar make_shared, utilize uma nova expressão explícita para criar o objeto antes do passar para o construtor de shared_ptr . O exemplo a seguir mostra várias formas de declarar e inicializar shared_ptr junto com um novo objeto.
// Use make_shared function when possible.
auto sp1 = make_shared<Song>(L"The Beatles", L"Im Happy Just to Dance With You");
// Ok, but slightly less efficient.
// Note: Using new expression as constructor argument
// creates no named variable for other code to access.
shared_ptr<Song> sp2(new Song(L"Lady Gaga", L"Just Dance"));
// When initialization must be separate from declaration, e.g. class members,
// initialize with nullptr to make your programming intent explicit.
shared_ptr<Song> sp5(nullptr);
//Equivalent to: shared_ptr<Song> sp5;
//...
sp5 = make_shared<Song>(L"Elton John", L"I'm Still Standing");
O exemplo a seguir mostra como declarar e inicializar as instâncias de shared_ptr que usam compartilhada na propriedade de um objeto que já foi atribuído por outro shared_ptr. Suponha que sp2 é shared_ptrinicializado.
//Initialize with copy constructor. Increments ref count.
auto sp3(sp2);
//Initialize via assignment. Increments ref count.
auto sp4 = sp2;
//Initialize with nullptr. sp7 is empty.
shared_ptr<Song> sp7(nullptr);
// Initialize with another shared_ptr. sp1 and sp2
// swap pointers as well as ref counts.
sp1.swap(sp2);
shared_ptr também é útil em contêineres padrão de (STL) da biblioteca de modelo quando você estiver usando os algoritmos que copia os elementos. Você pode envolver os elementos em shared_ptr, e copie-o em outros contêineres com entendimento que a memória subjacente é válido à medida que o necessário, e mais. O exemplo a seguir mostra como usar o algoritmo de replace_copy_if em instâncias de shared_ptr em um vetor.
vector<shared_ptr<Song>> v;
v.push_back(make_shared<Song>(L"Bob Dylan", L"The Times They Are A Changing"));
v.push_back(make_shared<Song>(L"Aretha Franklin", L"Bridge Over Troubled Water"));
v.push_back(make_shared<Song>(L"Thal�a", L"Entre El Mar y Una Estrella"));
vector<shared_ptr<Song>> v2;
remove_copy_if(v.begin(), v.end(), back_inserter(v2), [] (shared_ptr<Song> s)
{
return s->artist.compare(L"Bob Dylan") == 0;
});
for (const auto& s : v2)
{
wcout << s->artist << L":" << s->title << endl;
}
Você pode usar dynamic_pointer_cast, static_pointer_cast, e const_pointer_cast para converter shared_ptr. Essas funções lembram a dynamic_cast, a static_cast, e a operadores de const_cast . O exemplo a seguir mostra como testar o tipo derivado de cada elemento em um vetor de shared_ptr das classes base, e copiar os elementos e exibir informações sobre eles.
vector<shared_ptr<MediaAsset>> assets;
assets.push_back(shared_ptr<Song>(new Song(L"Himesh Reshammiya", L"Tera Surroor")));
assets.push_back(shared_ptr<Song>(new Song(L"Penaz Masani", L"Tu Dil De De")));
assets.push_back(shared_ptr<Photo>(new Photo(L"2011-04-06", L"Redmond, WA", L"Soccer field at Microsoft.")));
vector<shared_ptr<MediaAsset>> photos;
copy_if(assets.begin(), assets.end(), back_inserter(photos), [] (shared_ptr<MediaAsset> p) -> bool
{
// Use dynamic_pointer_cast to test whether
// element is a shared_ptr<Photo>.
shared_ptr<Photo> temp = dynamic_pointer_cast<Photo>(p);
return temp.get() != nullptr;
});
for (const auto& p : photos)
{
// We know that the photos vector contains only
// shared_ptr<Photo> objects, so use static_cast.
wcout << "Photo location: " << (static_pointer_cast<Photo>(p))->location_ << endl;
}
Você pode passar shared_ptr para outra função das seguintes maneiras:
Passe shared_ptr pelo valor. Isso invoca o construtor de impressão, incrementa a contagem de referência, e torna o destinatário um proprietário. Há uma pequena quantidade de sobrecarga nesta operação, que pode ser significante dependendo de quantos objetos de shared_ptr você estiver passando. Use essa opção quando o contrato de código (explícito ou implícito) entre o chamador e o destinatário requer que o destinatário seja um proprietário.
Passe shared_ptr por referência ou pela referência de const. Nesse caso, a contagem de referência não é incrementada, e o destinatário pode acessar o ponteiro como o chamador não sair do escopo. Ou, o destinatário pode decidir criar shared_ptr com base na referência, e se tornar bem assim em um proprietário compartilhado. Use esta opção quando o chamador não tem conhecimento do destinatário, ou quando você deverá passar shared_ptr e deseja para evitar a operação de cópia por motivo de desempenho.
Passar o ponteiro subjacente ou uma referência ao objeto subjacente. Isso permite que o destinatário para usar o objeto, mas não permite compartilhar a propriedade ou estender o tempo de vida. Se o destinatário cria shared_ptr do ponteiro bruto, nova shared_ptr é independente do original, e não controla o recurso subjacente. Use essa opção quando o contrato entre o chamador e o destinatário claramente especifica que o chamador o reterá a propriedade de tempo de vida de shared_ptr .
Quando você estiver decidindo como passar shared_ptr, determina se o destinatário tem que compartilhar a propriedade de recurso subjacente. Um “owner” é um objeto ou função que possa manter o recurso subjacente ativo desde que o precisa. Se o chamador precisa garantir que o destinatário pode estender a vida do ponteiro (além de seu tempo de vida da função), use a primeira opção. Se você não precisa se preocupar se o destinatário estende o tempo de vida, a passagem por referência e deixe que o destinatário copie-o ou não.
Se você tem que fornecer a um auxiliar acesso da função ao ponteiro subjacente, e você souber que a função auxiliar apenas usará o ponteiro e retornará antes da função de chamada retornar, depois que a função não tem que compartilham a propriedade do ponteiro subjacente. Somente precisa acessar o ponteiro no tempo de vida de shared_ptrdo chamador. Nesse caso, é seguro shared_ptr passar por referência, ou passar o ponteiro bruto ou uma referência ao objeto subjacente. Transmitir essa maneira fornece um pequeno benefício de desempenho, e também pode ajudar a expressar a intenção de programação.
Às vezes, por exemplo em std:vector<shared_ptr<T>>, você pode ter que transmitir cada shared_ptr a um corpo da expressão de lambda ou a um objeto denominado da função. Se o lambda ou função não estiver armazenando o ponteiro, então passar shared_ptr em função da evitar invocar o construtor de cópia para cada elemento.
O exemplo a seguir mostra como shared_ptr sobrecarregar vários operadores de comparação para habilitar comparações de ponteiro na memória que pertence a instâncias de shared_ptr .
// Initialize two separate raw pointers.
// Note that they contain the same values.
auto song1 = new Song(L"Village People", L"YMCA");
auto song2 = new Song(L"Village People", L"YMCA");
// Create two unrelated shared_ptrs.
shared_ptr<Song> p1(song1);
shared_ptr<Song> p2(song2);
// Unrelated shared_ptrs are never equal.
wcout << "p1 < p2 = " << std::boolalpha << (p1 < p2) << endl;
wcout << "p1 == p2 = " << std::boolalpha <<(p1 == p2) << endl;
// Related shared_ptr instances are always equal.
shared_ptr<Song> p3(p2);
wcout << "p3 == p2 = " << std::boolalpha << (p3 == p2) << endl;