Заставить shared_ptr потерять владение памятью - PullRequest
0 голосов
/ 13 июня 2018

У меня есть shared_ptr<MyProto>, который я передаю.В конце концов, в определенных ситуациях я хочу передать необработанный указатель на функцию, которая затем становится владельцем памяти.В этих случаях shared_ptr больше не отвечает за освобождение памяти, потому что функция, которую я вызываю, вступила во владение.Как заставить shared_ptr потерять владение?

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

Пример:

shared_ptr<MyProto> myProtoSharedPtr = // by this point this is the last reference to the heap allocated MyProto

// I want to add it to a collection and serialize the collection without copying
CollectionProto collectionProto;
collectionProto.mutable_my_proto().AddAllocated(myProtoSharedPtr.get()); // at this point collectionProto took ownership of the memory
std::string serialization = collectionProto.SerializeAsString();

// bad: myProtoSharedPtr.get() will be freed twice

Ответы [ 5 ]

0 голосов
/ 13 июня 2018

Вместо копирования вы можете переместить его в new редактируемый объект.

MyProto * myProto = new MyProto(std::move(*mySharedProto));

CollectionProto collectionProto;
collectionProto.mutable_my_proto().AddAllocated(myProto);

Вы также можете проверить, примет ли CollectionProto его значение

CollectionProto collectionProto;
collectionProto.mutable_my_proto().Add(std::move(*mySharedProto));
0 голосов
/ 13 июня 2018

Вы можете использовать std :: move, когда хотите передать право собственности, см. Следующий пример

#include <iostream>
#include <memory>
void take_ownership(std::shared_ptr<int> ptr){
std::cout<<ptr.use_count()<<" == 2\n";
} // destroying it


int main()
{
std::shared_ptr<int> p=std::make_shared<int>(1);
std::shared_ptr<int> p2(p);
//p is valid                                                                                                                                                                                                                                                                              
if(!p.get())
std::cout<<"error\n";
else
std::cout<<"OK\n";

//use p, p2

take_ownership(std::move(p));
//p is invalid                                                                                                                                                                                                                                                                            
if(!p.get())
std::cout<<"OK\n";
else
std::cout<<p.use_count()<<" error\n";

}
0 голосов
/ 13 июня 2018

Вам нужно будет предоставить std::shared_ptr пользовательское средство удаления (см. Конструктор 4).Затем вы можете определить удалитель, чтобы делать то, что вы хотите.В том числе, не уничтожайте ваш объект.

Примечание 1: я не рекомендую использовать shared_ptr здесь, но это способ сделать то, что вы хотите.

Примечание 2: Если вы используете make_shared для создания своих объектов, вы, скорее всего, столкнетесь с проблемами правильного удаления памяти после удаления последнего shared_ptr.

0 голосов
/ 13 июня 2018

Я думаю, что вы можете достичь того, что вы хотите сделать, разделяя a уникальный указатель следующим образом:

std::shared_ptr<std::unique_ptr<MyProto>> myProtoSharedUniquePtr;

Доступ к нему будет более косвенным:

(*myProtoSharedUniquePtr)->do_stuff();

Но вы могли бы вступить во владение так:

CollectionProto collectionProto;
collectionProto.mutable_my_proto().AddAllocated(myProtoSharedUniquePtr->release()); // at this point collectionProto took ownership of the memory
std::string serialization = collectionProto.SerializeAsString();

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

Вы уверены, что std::unique_ptr не будет лучше для ваших нужд?

0 голосов
/ 13 июня 2018

Вы можете использовать unique_ptr, который в любом случае лучше подходит для передачи памяти:

unique_ptr<MyProto> myProtoSharedPtr = // create MyPorto object

CollectionProto collectionProto;

// unique_ptr::release returns the pointer and
// releases the ownership of the MyProto object
collectionProto.mutable_my_proto().AddAllocated(myProtoSharedPtr.release());

std::string serialization = collectionProto.SerializeAsString();
...