将智能指针用作类成员

Using smart pointers as a class member

本文关键字:成员 智能 指针      更新时间:2023-10-16

我一直在阅读智能指针,最近在课堂上,我的TA说我们永远不应该使用原始指针。现在,我在网上读了很多书,在这个网站上看了不同的问题,但我仍然对智能指针的某些方面感到困惑。我的问题是:如果我想在我的程序中使用哪个智能指针?我会展示一些代码。

因此,我有一个基本的Application类,它对类AI中的对象进行声明。注意:出于测试的原因,我有两个不同的智能指针,一个是唯一的,另一个是共享的。

// Application class in Application.h
class Application
{
public:
    Application(){}
    ~Application(){}
    //... additional non-important variables and such
    unique_ptr<AI> *u_AI; // AI object using a unique pointer
    shared_ptr<AI> *s_AI; // AI object using a shared pointer
    //... additional non-important variables and such
    void init();
    void update();
};
// AI class in AI.h
class AI
{
public:
    AI(){}
    ~AI(){}
    bool isGoingFirst;
};

在Applicationinit函数中,我想创建AI对象,然后在更新函数中使用它。我不确定我是否完全正确地声明了我的指针,但我知道它可以编译,并且可以在init函数中分配和打印数据。下面是更多代码。

void Application::init()
{
    //.. other initialization's.
    std::shared_ptr<AI> temp(new AI());
    sh_AI = &temp;
    sh_AI->isGoingFirst = true;
    //.. other initialization's.
    // Function ends.
}
void Application::update()
{
    if(sh_AI->get()->isGoingFirst == true)
    {
         // Do something
    }
    else
    {
        // Do something else
    }
    // Other code below
}

稍后在我的程序中,会调用update函数,它使用我在类Application中声明的相同AI智能指针。我发现智能指针AI对象正在被删除。我知道智能指针有自动内存管理功能,但有没有一种智能指针可以让你在不同的函数中使用it,而不会产生任何重大问题,比如内存泄漏或悬空引用?还是我错过了智能指针的全部要点?

如果这在另一个问题中得到了回答,我很抱歉,但我读了很多其他问题,虽然我对智能指针有了更多的了解,但我仍在学习。非常感谢。

正如Neil Kirk在评论中指出的,这些声明不是你想要的:
unique_ptr<AI> *u_AI; // AI object using a unique pointer
shared_ptr<AI> *s_AI; // AI object using a shared pointer

uAI和s_ AI仍然是原始指针的对象。关键是不需要直接管理原始指针。所以现在你用代替它们

unique_ptr<AI> u_AI; // AI object using a unique pointer
shared_ptr<AI> s_AI; // AI object using a shared pointer

要分配创建的指针,可以使用函数make_unique或make_shared:

u_AI = unique_ptr<AI>(new AI()); // Yu may be able to use make_unique like 
                                 // make_shared but it's new to C++14. may not be available
s_AI = make_shared<AI>();

然后,当你需要访问它们时,你只需要假装它们是指针,所以在你的更新函数中:

if(sh_AI->get()->isGoingFirst == true)

变为:

if(sh_AI->isGoingFirst == true)

至于何时使用unique_ptr与shared_ptr,您可以回答以下问题:当有人复制Application时,我希望发生什么?即:

Application app1;
app1.init();
Application app2 = app1; // ?? what happens to AI object in app2?

有3种可能的答案:

  1. 我希望在app2中有一个额外的AI副本。在这种情况下,您使用unique_ptr,并确保实现了一个执行复制的复制构造函数
  2. 我希望app2和app1共享AI的副本。在这种情况下,您使用shared_ptr,默认的副本构造函数将为您完成任务
  3. 我不希望有一份应用程序的副本(这对于一个名为Application的类来说是有意义的)。在这种情况下,这并不重要(在这种情况中,我会默认为unique_ptr),并删除复制构造函数:

    Application(const Application&)=删除;

简短回答:由于您的指针是公共的,我建议您使用shared_ptr。但是,您的指针不需要是公共的,所以如果它是私有的,您可以使用unique_ptr,因为您只在自己的实例中使用它。

但事实是,这其实并不重要(我知道我会因此得到一些反对票)。使用unique_ptr有两个原因:

  1. 它永远不会离开你的模块,你只需要一个裸指针的替代品
  2. 您想要明确地表明它不应该离开您的模块

另一方面,如果您需要共享指针(即使是以只读方式),则必须使用shared_ptr

很多时候,首先使用shared_ptr更方便,但由于上述原因2),值得使用unique_ptr

不是使用unique_ptr的理由:性能。我只说make_shared

现在转到您的代码

这就是定义智能指针的方式:

std::shared_ptr<AI> s_AI;
std::unique_ptr<AI> u_AI;

这就是初始化它的方式:

s_AI = std::make_shared<AI>(); // or
s_AI = std::shared_ptr<AI>(new AI);
u_AI = std::unique_ptr<AI>(new AI);

请注意,在C++11中没有std::make_unique。它将在C++14中,编写一个替换并不难,但事实是在C++11中并没有。

这就是你如何使用指针:

s_AI->isGoingFirst;

就是这样,它的行为就像一个普通的指针。只有当您必须将它传递给需要指针的函数时,才需要使用.get()

以下是删除(清空)指针的方法:

s_AI.reset();

再次,我建议您将指针设为私有指针。如果您需要传递它,请确保使用shared_ptr并编写一个getter方法:

std::shared_ptr<AI> getAI() const {
    return s_AI;
}

请记住,如果你这样做,你就不能假设当你的应用程序对象是时,你的AI对象会被破坏