C++ 创建用于堆栈对象的共享\u ptr

C++ 创建用于堆栈对象的共享\u ptr,c++,c++11,shared-ptr,smart-pointers,C++,C++11,Shared Ptr,Smart Pointers,在我的方法中,创建的播放器对象如下所示: Player player(fullName,age); 我的老师给了我们一段代码,其中包含一个构造函数,它将一个共享的ptr带到一个player对象 //constructor of the class SomeClass(const std::shared_ptr<Socket> client, std::shared_ptr<Player> player) //类的构造函数 SomeClass(const std::sh

在我的方法中,创建的播放器对象如下所示:

Player player(fullName,age);
我的老师给了我们一段代码,其中包含一个构造函数,它将一个共享的ptr带到一个player对象

//constructor of the class
SomeClass(const std::shared_ptr<Socket> client, std::shared_ptr<Player> player)
//类的构造函数
SomeClass(const std::shared_ptr client,std::shared_ptr player)
假设我们想调用SomeClass的构造函数并传递我们在堆栈上创建的player对象

从堆栈对象创建共享\u ptr是否安全/可能/良好

为了让问题更容易理解,假设我们有两个大型代码项目,我们希望合并它们,以便从一个项目调用另一个项目中的方法,我们是否应该重写所有文件以独占地使用共享\u ptr或堆栈对象(对于需要连接的方法)或者我们应该为堆栈对象创建一个共享的ptr

为什么我不确定结果:

如果创建stackobject的范围结束了,但共享的_ptr仍在使用,反之亦然,该怎么办

stackobject在超出范围时被删除,还是因为仍然存在对该对象的引用而保持活动状态(尽管在另一个类中)

shared_ptr超出范围并尝试删除该对象,即使stackobject正在引用它,它也能删除吗

注意:我知道我可以使用下面的传球球员

shared_ptr player{新玩家{全名,年龄};

创建指向堆栈对象的共享指针是不安全的,因为堆栈对象在其包含函数返回后将立即销毁。本地对象是隐式自动分配和解除分配的,尝试干预肯定会调用许多未定义的行为

从堆栈对象创建智能ptr是否安全/可能/良好

安全?只有当您能够保证创建该对象的堆栈只有在所有
共享的\u ptr
伪拥有该对象之后才会结束时,才可以这样做

是否可能?确定:向共享的构造函数传递一个不执行任何操作的删除对象:

auto sptr = shared_ptr<Player>(&player, [](Player *) {});
auto-sptr=shared_ptr(&player,[](player*){});
当最后一个
共享\u ptr
被销毁时,将调用删除程序,并且不会删除任何内容

?不是真的。如上所述,安全性并不是这种代码中可以普遍保证的东西。根据您的代码结构,这可能是合法的。但这需要非常小心


SomeClass
期望声明资源的所有权;这就是为什么它需要一个
共享的\u ptr
。你给它传递了一个
shared\u ptr
,但它并不真正拥有它引用的对象,这有点欺骗它。这意味着您和您的代码结构有责任不违反您向
SomeClass
作出的承诺,即它将对该对象的生命周期具有共享控制权。

共享指针的目的是管理动态创建的对象的生命周期。只要存在指向某个对象的共享指针,该对象就必须仍然存在;当指向对象的最后一个共享指针被销毁时,该对象将被销毁

堆栈对象有一个根本不同的生存期:它们一直存在,直到代码从创建它们的作用域中退出,然后被销毁

生命周期的两个概念是不兼容的:共享指针无法确保超出范围的堆栈对象仍然存在


所以不要把两者混为一谈。

安全是一个强有力的词。 但是,通过定义StackObjectSharedPtr,强制共享的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());
使用PlayerStackSP=std::shared\u ptr;
类StackObjectDeleter{
公众:
void运算符()(void*)常量{}
};
玩家(全名、年龄);
std::shared_ptr player(&player,StackObjectDeleter());
StackObjectDeleter将默认的_delete替换为deleter对象。默认的_delete只调用delete(或delete[])。在StackObjectDeleter的情况下,不会发生任何事情

这比@Nicol Bolas的答案更进一步

从堆栈对象创建共享\u ptr是否安全/可能/良好

我同意尼古拉斯·博拉斯的说法,那是不安全的。但从堆栈对象的副本创建共享\u ptr可能是安全的

shared_ptr<Player> playerPtr(new Player(player));
shared_ptr playerPtr(新玩家(玩家));
当然,如果播放机是可复制的。

使用移动语义创建共享\u ptr
std::shared_ptr player_shared_ptr{std::make_shared(std::move(player))};

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

如果您使用的是c++11或更高版本,最好在可能的情况下使用
make_shared
。在这种情况下:
autoplayer=std::make_shared(全名,年龄)在大多数情况下,它更高效、更安全。为什么复制不是一个更被接受的答案?我目前正在处理一个只能使用返回对象实例的静态函数创建的对象。据我所知,获取指向此的共享指针的唯一方法是使用
std::make_shared(Foo::create(args))
,我相信它将调用Foo::create,在堆栈上返回一个Foo,然后将Foo复制到共享的ptr中。
shared_ptr<Player> playerPtr(new Player(player));
std::shared_ptr<Player> player_shared_ptr{ std::make_shared(std::move(player)) };