c ++创建shared_ptr到堆栈对象

时间:2016-08-09 15:52:20

标签: c++ c++11 shared-ptr smart-pointers

在我的方法中,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} };

6 个答案:

答案 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)

使用移动语义来创建shared_ptr

std::shared_ptr<Player> player_shared_ptr{ std::make_shared(std::move(player)) };

这样,就避免了复制。您可能需要在相关类上实现move构造函数,此方法才能起作用。大多数/所有std对象都支持开箱即用地移动语义(例如stringvector等)