2016-08-09 5 views
2

В моем методе объект игрока создается как:C++ создать shared_ptr в стек объекта

Player player(fullName,age); 

Мой учитель дал нам кусок кода с конструктором, который принимает shared_ptr для объекта игрока.

//constructor of the class 
SomeClass(const std::shared_ptr<Socket> client, std::shared_ptr<Player> player) 

Допустим, мы хотим вызвать конструктор SomeClass и передать объект игрока, который мы создали в стеке.

Действительно ли безопасно/возможно/полезно создать shared_ptr из объекта стека?

Чтобы сделать вопрос более понятным, скажем, что у нас есть два больших проекта кода, и мы хотим их объединить, поэтому метод из одного проекта вызывается из другого, мы должны переписать все файлы, чтобы использовать shared_ptr или стек объекты exclusivly (для методов, которые необходимо подключить) или мы должны просто создать shared_ptr для объекта стека.

Почему им не уверены в результате:

Что делать, если сфера, где stackobject создается заканчивается, но shared_ptr все еще используется, и наоборот.

Элемент stackobject удаляется из-за пределов видимости или остается в живых, потому что все еще есть ссылка на объект (в другом классе)?

Share_ptr выходит из области видимости и пытается удалить объект, может ли он даже ссылаться на файл stackobject?

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

shared_ptr<Player> player{ new Player {fullName,age} }; 
+0

Возможный дубликат [Установить общий \ _ptr для указания существующего объекта] (http://stackoverflow.com/questions/24049155/set-shared-ptr-to-point-existing-object) – Zereges

+0

Сторона примечания, если вы находитесь в C++ 11 или новее, это хорошая привычка использовать 'make_shared', когда сможете. в этом случае: 'auto player = std :: make_shared (fullName, age);' В большинстве случаев он более эффективен и безопаснее. –

ответ

9

Действительно ли безопасно/возможно/полезно создать smart_ptr из объекта стека?

Safe? Только если вы можете гарантировать, что стек, создавший этот объект, будет завершен только после того, как все shared_ptr с псевдо-импортом.

Возможно? Конечно: передать конструктору shared_ptr «s объект DeleteR, который ничего не делает:

auto sptr = shared_ptr<Player>(&player, [](Player *) {}); 

Когда последний shared_ptr разрушен, Deleter будет называться, и ничто не будет удалено.

Хорошо? На самом деле, нет. Как отмечалось выше, безопасность не является чем-то, что может быть универсально гарантировано в таком коде. В зависимости от структуры кода это может быть законным. Но это требует большой осторожности.

Этот SomeClass ожидает получения права собственности на ресурс; поэтому он принимает shared_ptr. Вы как бы лгали ему, передавая ему shared_ptr, который действительно не владеет объектом, на который он ссылается. Это означает, что бремя ответственности за то, что вы и ваша структура кода не нарушили обещание, которое вы сделали до SomeClass, что он будет иметь общий контроль над временем жизни этого объекта.

2

Это не безопасно, чтобы создать общий указатель на объект стека, так как объект стека из-за разрушения, как только возвращается его содержащая функция. Локальные объекты выделяются и освобождаются неявно и автоматически и пытаются вмешаться, безусловно, вызывают много видов неопределенного поведения.

1

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

Объекты стека имеют принципиально иное время жизни: они существуют до тех пор, пока код не выйдет из области, в которой они были созданы, а затем они уничтожены.

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

Так что не смешивайте два.

0

Safe - сильное слово. Однако, Вы можете сделать код более безопасным путем определения StackObjectSharedPtr, заставляя shared_ptr инстанциирован типа, чтобы включить «специальный» StackObjectDeleter

using PlayerStackSP = std::shared_ptr <Player, StackObjectDeleter> ; 

class StackObjectDeleter { 
public: 
    void operator() (void*) const {} 
}; 

Player player(fullName,age); 
std::shared_ptr<PlayerStackSP, StackObjectDeleter> player(&player, StackObjectDeleter()); 

StackObjectDeleter заменяет default_delete как объект DeleteR. default_delete просто вызывает delete (или delete []). В случае StackObjectDeleter ничего не произойдет.

Это шаг дальше от ответа @Nicol Bolas.