Поделиться через


Практическое руководство. Создание и использование экземпляров shared_ptr

Тип shared_ptr интеллектуального указателя в C стандартной библиотеке C++, которая предназначена для сценариев, в которых несколько владелец может управлять временем существования объекта в памяти. После инициализации shared_ptr можно скопировать, передает его значение в аргументах функции и присвоить его другим экземплярам shared_ptr. Все экземпляры указывают на один объект, и используют доступ к одному «блок элемента управления» эти этапы и декременты счетчик ссылок при создании нового shared_ptr добавляется, выходит за пределы области, или сброшены. Когда число ссылок достигает нуля, блок элемента управления сам памяти и удаляет ресурс.

На следующем рисунке показаны несколько экземпляров shared_ptr, указывающих на одно расположение в памяти.

Общий указатель

Пример

Если возможно, используйте функцию make_shared (<memory>) для создания shared_ptr при ресурс памяти создается в первый раз. make_shared исключений безопасным образом. Он использует тот же вызов для распределения памяти для блока элементов управления и ресурсов, поэтому снижает нагрузку на систему построения. Если не используется make_shared, необходимо использовать явное новое выражение для создания объекта до его необходимо передать в конструктор shared_ptr. В следующем примере показаны различные способы объявления и инициализации shared_ptr вместе с новым объектом.

// 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");

В следующем примере показано, как объявить и инициализировать экземпляры shared_ptr, принимающие на общий владельца объекта, который уже был выбран другой shared_ptr. Высказывать sp2 инициализированное shared_ptr.

//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 полезно в контейнерах (STL) стандартной библиотеки шаблонов при использовании алгоритмы, скопируйте элементы. Элементы можно использованих программы-оболочек в shared_ptr, а затем скопируйте его в другие контейнеры, команда должна понимать, что основной памяти допустима, если это необходимо, и не. В следующем примере показано, как использовать алгоритм replace_copy_if в экземплярах shared_ptr в векторе.

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;
}

Можно использовать dynamic_pointer_cast, static_pointer_cast и const_pointer_cast приведение shared_ptr. Эти функции похожи на dynamic_cast, static_cast и операторы const_cast. В следующем примере показано, как выполнить производный тип каждого элемента в векторе shared_ptr базовых классов, а затем скопировать элементы и отображение информации о них.

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;
}

Можно передать shared_ptr другой функции следующими способами:

  • Передайте shared_ptr значение. Это вызывает конструктор копии, увеличивает счетчик ссылок и делает вызываемым объектом владельца. Минимальный объем нагрузки в этой операции, которая может быть значительно в зависимости от количества объектов shared_ptr при передаче. Этот параметр следует использовать, когда контракт кода (явный или неявный) между вызывающим и вызываемым объектами требует вызываемый объект dbo.

  • Передайте shared_ptr ссылкой или константной. В этом случае число ссылок не инкрементирован и вызываемый объект может получить указатель, если вызывающий объект не выходит за пределы области действия. Или, вызываемый объект может потребоваться создание shared_ptr на основе ссылки, и поэтому переход общий dbo. Используйте этот параметр, если вызывающий объект не имеет статью вызываемого объекта, или при необходимости передать shared_ptr и хотелось бы избежать копирования для повышения производительности.

  • Передайте основной указатель или ссылку к базовому объекту. Это позволяет использовать объект вызываемый объект, но не позволяет использовать его владельца или продлить время существования. Если вызываемый объект создает shared_ptr из начального указателем, новое shared_ptr независимо от исходного и не делает элемент управления является основным ресурсом. Этот параметр следует использовать, когда контракт между вызывающим и вызываемым объектом, указывает, что вызывающий объект сохраняет владение времени существования shared_ptr.

  • При принятии решения о том, как передавать shared_ptr, определения, должен ли вызываемый объект владельца основного совместное использование ресурсов. «Владелец» объект или функция которого может хранить основной ресурс в активном состоянии, пока ему нужно. Если вызывающий объект должен гарантировать, что вызываемый объект можно расширить жизненный указателя за его (времени существования функции), используйте первый вариант. Если не заботите, увеличивает ли вызываемый объект время существования, а затем передать по ссылке и оставляет вызываемому объекту копирования или нет.

  • Если необходимо предоставить доступ к базовому вспомогательной функции указателя, и известно, что вспомогательная функция просто будет использовать указатель и будет возвращать до вызывающая функция возвращает, то, что функция не должна использовать владельца основного указателя. Она просто должна получить указатель за время существования shared_ptr вызывающего объекта. В этом случае безопасно передавать shared_ptr по ссылке, или передайте необработанный указатель или ссылку к базовому объекту. Этот способ передачи предоставляет небольшое преимущество в производительности, а также может помочь представить в программировании предназначение.

  • В некоторых случаях, например в std:vector<shared_ptr<T>>, можно передать каждое shared_ptr к объекту или именованной тела функции лямбда-выражения. Если лямбда-выражение или функция не сохраняет указатель, передайте shared_ptr в отношении избегайте вызова конструктора для каждого элемента.

В следующем примере показано, как shared_ptr в различных операторов сравнения для включения сравнения указателя на память, которая принадлежит экземплярами 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; 

См. также

Основные понятия

Интеллектуальные указатели (современный C++)