使用智能指针作为类成员

时间:2014-10-20 19:49:27

标签: c++ pointers memory-management smart-pointers

我一直在阅读智能指针,最近在课堂上我的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;
};

在Application init函数中,我想创建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对象正在被删除。我知道智能指针有自动内存管理,但是有一个智能指针,允许你在不同的功能中使用它而不会产生任何重大问题,如内存泄漏或悬空引用?或者我错过了智能指针的全部内容?

对不起,如果在另一个问题中回答了这个问题,但我读了很多其他问题,虽然我对智能指针有了更多了解,但我还在学习。谢谢!

2 个答案:

答案 0 :(得分:8)

正如Neil Kirk在评论中指出的那样,这些声明不是你想要的:

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

u_AI和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 vs shared_ptr,您可以通过回答以下问题来回答:当有人复制Application时,我想要发生什么?即:

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

有三种可能的答案:

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

    应用程序(const Application&amp;)=删除;

答案 1 :(得分:-1)

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

事实是,这并不重要(而且我知道我会得到一些事情)。使用unique_ptr有两个原因:

  1. 它永远不会离开你的模块而你只需要替换裸指针
  2. 你想明确表明它不应该离开你的模块。
  3. 另一方面,如果你需要共享指针(即使是以只读方式),那么你将不得不使用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对象在你的Application对象被销毁时会被销毁。