在C ++中使用shared_ptr时,use_count变为-1

时间:2018-11-25 12:31:22

标签: c++ pointers memory shared-ptr

GenericStack.h

#ifndef _GENERIC_STACK_TROFIMOV_H_
#define _GENERIC_STACK_TROFIMOV_H_

#include <memory>

class GenericStack {
    struct StackNode {
        std::shared_ptr<void> _data; 
        StackNode* _next;
        StackNode(const std::shared_ptr<void>& p, StackNode* next) 
            : _data(p), _next(next) {

        }
    };
    StackNode* _top; 

    GenericStack(const GenericStack&);
    GenericStack& operator=(const GenericStack&);

protected:
    GenericStack();
    ~GenericStack();
    void push(const std::shared_ptr<void>&);
    void pop();
    std::shared_ptr<void>& top();
    bool isEmpty() const;

public:
    class EmptyError {
        const char* _message;
    public:
        EmptyError(const char* message)
            : _message(message) {

        }
        const char* getMessage() const {
            return _message;
        }
    };
};

template <class T>
class TStack: private GenericStack {                  
public:
    void push(const std::shared_ptr<T>& p) { GenericStack::push(p); }
    void pop() { GenericStack::pop(); }
    std::shared_ptr<T>& top() { return std::static_pointer_cast<T>(GenericStack::top()); }
    bool isEmpty() const { return GenericStack::isEmpty(); }
};

#endif

GenerickStack.cpp

#include "GenericStack.h"

GenericStack::GenericStack()
    : _top(0) {

};
GenericStack::~GenericStack() {
    while(!isEmpty()) {
        pop();
    }
};

void GenericStack::push(const std::shared_ptr<void>& p) {
    _top = new StackNode(p, _top);
}

std::shared_ptr<void>& GenericStack::top() {
    if(isEmpty()) {
        throw EmptyError("No more elements in stack.");
    }
    return _top->_data;
}
void GenericStack::pop() {
    if(isEmpty()) {
        throw EmptyError("No more elements in stack.");
    }

    StackNode* t = _top->_next;
    delete _top;
    _top = t;
}

bool GenericStack::isEmpty() const {
    return !_top;
}

Main.cpp

#include <iostream>
#include "GenericStack.h"
//#define NDEBUG
#include <assert.h>

void ordinaryUsageVerification() {
    TStack<int> intStack;

    {
        std::shared_ptr<int> sh(new int(7));
        intStack.push(sh);
        intStack.isEmpty();
        assert(!intStack.isEmpty() && sh.use_count() == 2);
    }
    //assert(!intStack.isEmpty() && intStack.top().use_count() == 1);
    std::cout << "intStack.top().use_count(): " << intStack.top().use_count() << std::endl;

    std::cout << "*gs.top(): " << *intStack.top() << std::endl;
    intStack.pop();
    assert(intStack.isEmpty());
}


int main() {
    ordinaryUsageVerification();

    return 0;
}

Main.cpp 中的以下两行之后:

std::shared_ptr<int> sh(new int(7));
intStack.push(sh);

我期望intStack.top().use_count()等于2,但等于-1。

我期望这样的行为,因为在调用push方法时,我是通过引用传递shared_ptr的,因此use_count不应更改。并且仅在 GenericaStack.h 中的一个位置:

StackNode(const std::shared_ptr<void>& p, StackNode* next) 
            : _data(p), _next(next) {

{{1}的use_count递增1。

因此,鉴于在p之前我有push,在sh.use_count() == 1之后我有intStack.push(sh);我应该得到sh.use_count() == 2,但是我得到的是{ {1}}。为什么?

谢谢。

以这种方式修改 GenericStack.h 后:

intStack.top().use_count() == 2

我遇到错误:

  

错误1错误C2664:'GenericStack :: push':无法将参数1从'std :: shared_ptr <_Ty>'转换为'std :: shared_ptr <_Ty>&'... \ stack \ genericstack.h 47堆叠

关于这部分:

intStack.top().use_count() == -1

1 个答案:

答案 0 :(得分:0)

让我们回顾一下specification of std::static_pointer_caststd::static_pointer_cast()返回一个右值,也就是一个临时对象。

std::shared_ptr<T>& top() { return std::static_pointer_cast<T>(GenericStack::top()); }

这返回对临时对象的引用,该引用在此top()返回时被销毁。未定义的行为。大多数现代C ++编译器通常都能够检测到这种未定义行为的常见实例,并且您的编译器应该在这一行上向您咆哮。

通常,尝试通过从void *(这组模板的明显潜在目的)来回转换事物来击败C ++的类型安全性-永远不会成功。