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

时间:2015-06-01 02:20:31

标签: c++ stack smart-pointers

从我的理解正确:

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

unique_ptr :没有开销,无法复制,可以移动。

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

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

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

我问这个问题的原因是因为unique_ptr和shared_ptr都无法复制,这正是我在简单堆栈的实现中所做的。我已经注释了//在这里我正在使用C ++指针的程序,如果你正确地阅读了程序,你会看到如何在几乎所有的函数中复制数据。

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;
}

2 个答案:

答案 0 :(得分:3)

以下是使用std::unique_ptr实现堆栈的方法。请注意使用std::move()重新分配std::unique_ptr,使原始指向无效。

此外,我使用了更惯用的if(topState == NULL),而不是if(topState)std::unique_ptr如果指向某处则返回true,否则返回false。

同样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();
}

答案 1 :(得分:0)

此处unique_ptr完全没问题,特别是如果您按原样返回CurrentGameState值。

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

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