在我的方法中,Player对象的创建方式如下:
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或独占地堆栈对象(对于需要连接的方法)或者我们应该只为堆栈对象创建一个shared_ptr。
为什么我不确定结果:
如果创建stackobject的范围结束但仍然使用shared_ptr,反之亦然。
当超出范围时,stackobject会被删除,或者它是否仍然存在,因为仍然存在对该对象的引用(但在另一个类中)?
shared_ptr超出范围并尝试删除对象,即使stackobject引用它也可以吗?
注意:我知道我可以使用以下内容并传递播放器
shared_ptr<Player> player{ new Player {fullName,age} };
答案 0 :(得分:18)
从堆栈对象创建smart_ptr是否安全/可能/好?
<强>安全强>?只有当你保证时,创建该对象的堆栈才会在伪拥有它的所有shared_ptr
之后结束。
<强>可能的强>?当然:将shared_ptr
的构造函数传递给不执行任何操作的删除对象:
auto sptr = shared_ptr<Player>(&player, [](Player *) {});
当最后一个shared_ptr
被销毁时,将调用删除器并且不会删除任何内容。
不可强>?并不是的。如上所述,在这种代码中,安全性不是普遍保证的。根据您的代码结构,这可能是合法的。但它需要非常小心。
此SomeClass
期望获得资源的所有权;这就是它采用shared_ptr
的原因。你通过传递一个shared_ptr
而不是真正拥有它所引用的对象,你会对它撒谎。这意味着您和您的代码结构上的责任不会违反您对SomeClass
的承诺,即它将共享对该对象生命周期的控制权。
答案 1 :(得分:2)
创建一个指向堆栈对象的共享指针是不安全的,因为堆栈对象一旦包含函数返回就会被破坏。本地对象被隐式地自动分配和释放,并且试图干预肯定会引发多种未定义的行为。
答案 2 :(得分:2)
共享指针的目的是管理动态创建的对象的生命周期。只要有指向对象的共享指针,该对象必须仍然存在;当指向对象的最后一个共享指针被销毁时,该对象将被销毁。
堆栈对象具有根本不同的生命周期:它们一直存在,直到代码退出创建它们的范围,然后它们被销毁。
生命周期的两个概念是不兼容的:共享指针无法确保超出范围的堆栈对象仍然存在。
所以不要混淆两者。
答案 3 :(得分:2)
从堆栈对象创建shared_ptr是否安全/可行/良好?
我同意@Nicolas Bolas的说法,这并不安全。但是从堆栈对象的副本创建一个shared_ptr可能是安全的
shared_ptr<Player> playerPtr(new Player(player));
如果播放器当然是可复制的。
答案 4 :(得分:0)
安全是一个强有力的词。 但是,您可以通过定义StackObjectSharedPtr使代码更安全,从而强制shared_ptr instanciated类型包含&#34;特殊&#34; 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_dele替换为删除对象。 default_delete只调用delete(或delete [])。在StackObjectDeleter的情况下,什么都不会发生。
这是@Nicol Bolas的答案的又一步。
答案 5 :(得分:0)
std::shared_ptr<Player> player_shared_ptr{ std::make_shared(std::move(player)) };
这样,就避免了复制。您可能需要在相关类上实现move构造函数,此方法才能起作用。大多数/所有std
对象都支持开箱即用地移动语义(例如string
,vector
等)