在 Stack 实现中使用哪个智能指针?

Which smart pointer to use in Stack implementation?

据我正确理解:

scoped_ptr: 无开销,无法复制或移动。

unique_ptr:无开销,不可复制,可移动。

shared_ptr: 一些开销(引用计数),可以复制。

话虽如此,如果需要多个所有者,则应使用shared_ptr。

现在,在下面的这个程序中,它是一个简单的 C++ 堆栈实现。我不明白应该使用哪种类型的智能指针。

我问这个问题的原因是 unique_ptr 和 shared_ptr 都不能被复制,而这正是我在这个简单堆栈的实现中所做的。我在我使用 C++ 指针的程序中注释掉了 //HERE,如果您正确阅读程序,您将看到数据是如何在几乎所有函数中被复制的。

GameStateStack.h

#ifndef _H_GAMESTATE_
#define _H_GAMESTATE_

#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <memory>

class node
{
public:
    std::string gameState;
    node * nextGameState;    // HERE
};

class GameStateStack
{
private:
    node * _topState;    // HERE
    void Destory();

public:
    int gameStatesCount;
    void PushGameState(std::string element);
    void PopGameState();
    std::string CurrentGameState();
    GameStateStack();
    ~GameStateStack();
};

extern GameStateStack state;

#endif

GameStateStack.cpp

#include <iostream>
#include <stdlib.h>
#include <string>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <memory>
#include "GameStateStack.h"
#include "template.h"

GameStateStack state;

GameStateStack::GameStateStack()
{
    _topState = NULL;
    gameStatesCount = 0;
}

GameStateStack::~GameStateStack()
{

}

void GameStateStack::PushGameState(std::string gameStateName)
{
    node *newTopState = new node;  // HERE
    if (_topState == NULL)
    {
        newTopState->gameState = gameStateName;
        newTopState->nextGameState = NULL;
        _topState = newTopState;
        gameStatesCount++;
    }

    else
    {
        newTopState->gameState = gameStateName;
        newTopState->nextGameState = _topState;
        _topState = newTopState;
        gameStatesCount++;
    }
}

void GameStateStack::PopGameState()
{
    if (_topState == NULL)
        std::cout << "Error: no gamestates available to pop";
    else
    {
        node * old = _topState;  // HERE
        _topState = _topState->nextGameState;
        delete(old);
        gameStatesCount--;
    }
}

std::string GameStateStack::CurrentGameState()
{
    node *temp;    // HERE
    temp = _topState;
    return temp->gameState;
}

void GameStateStack::Destory()
{
    node *abc;    // HERE
    delete _topState;
    delete abc->nextGameState;
}

这里 unique_ptr 非常好,特别是如果您 return 按值 CurrentGameState 时。

你的顶部应该是 unique_ptr<node>& 但由于开头没有状态你可以使用 std::reference_wrapper 来包装它。

当然,如果您打算 return 通过引用或指针访问游戏状态,情况就会发生变化,因为弹出状态会使包含的状态无效(除非它是动态分配然后设置的)。

以下是如何使用 std::unique_ptr 实现您的堆栈。请注意使用 std::move() 重新分配 std::unique_ptr 使原始指向空无一物。

此外,我使用了更惯用的 if(topState) 而不是 if(topState == NULL)。 A std::unique_ptr returns 如果指向某处则为真,否则为假。

另外 standard C++ 规定我们不应该以 _.

开头的变量名
#include <string>
#include <memory>
#include <iostream>

struct node
{
    std::string gameState;
    std::unique_ptr<node> nextGameState;

    ~node()
    {
        std::cout << "deleting: " << gameState << '\n';
    }
};

class GameStateStack
{
    // should not use _ to begin variable names in std C++
    std::unique_ptr<node> topState;
    int gameStatesCount;

public:
    GameStateStack();
    void PushGameState(std::string gameStateName);
    void PopGameState();
    std::string CurrentGameState();
    void Destory();
};

GameStateStack::GameStateStack()
: gameStatesCount(0) // initialize here
{
    //topState = NULL; // no need to initialize unique_ptr
    //gameStatesCount = 0; // not here
}

void GameStateStack::PushGameState(std::string gameStateName)
{
    std::unique_ptr<node> newTopState(new node);
    newTopState->gameState = gameStateName;

    newTopState->nextGameState = std::move(topState);
    topState = std::move(newTopState);

    gameStatesCount++;
}

void GameStateStack::PopGameState()
{
    if(!topState)
        std::cout << "Error: no gamestates available to pop";
    else
    {
        topState = std::move(topState->nextGameState);
        gameStatesCount--;
    }
}

std::string GameStateStack::CurrentGameState()
{
    if(topState)
        return topState->gameState;
    return "error: nothing on stack"; // error
}

void GameStateStack::Destory()
{
    // deleting topState will first destroy the pointed to
    // node's own unique_ptr<node> nextGameState
    // which in turn will first delete its own nextGameState etc...
    topState.reset();
}

int main()
{
    GameStateStack stack;

    std::cout << "\ndestroy test" << '\n';

    stack.PushGameState("a");
    stack.PushGameState("b");
    stack.PushGameState("c");
    stack.PushGameState("d");
    stack.PushGameState("e");
    stack.PushGameState("f");

    stack.Destory();

    std::cout << "\npush-pop test" << '\n';

    stack.PushGameState("a");
    stack.PushGameState("b");
    stack.PushGameState("c");

    std::cout << stack.CurrentGameState() << '\n';

    stack.PopGameState();

    stack.PushGameState("d");
    stack.PushGameState("e");

    std::cout << stack.CurrentGameState() << '\n';

    stack.PopGameState();

    std::cout << stack.CurrentGameState() << '\n';

    stack.PopGameState();

    std::cout << stack.CurrentGameState() << '\n';

    stack.PopGameState();

    std::cout << stack.CurrentGameState() << '\n';

    stack.PopGameState();

    std::cout << stack.CurrentGameState() << '\n';

    stack.PopGameState();
}