使用shared_ptr管理多个对象:C ++

时间:2015-02-19 09:10:52

标签: c++ c++11

我正在尝试编写Manager class来管理Test Class的多个实例。我应该可以通过调用Test Class来销毁mng.drop(shared pointer to the instance to be dropped)的实例。

我不应该使用unique_ptr如何使用shared_ptr

实施
#include <iostream>
#include <iomanip>
#include <memory>
#include <set>

#define DEBUG ON

#ifdef DEBUG
#define DEBUG_MSG(str) do {std::cout << std::setw(75) << std::left  << __FUNCTION__ \
    << std::setw(3) << std::left << ":" << std::setw(5) << std::left << __LINE__ \
    << std::setw(5) << std::left << ":"\
    << std::left  << str \
    << std::endl;} while( false )
#else
#define DEBUG_MSG(str) do { } while ( false )
#endif


class Test{
public:
    Test(int i) : i_(i){
        DEBUG_MSG("Constructor");
    }
    ~Test(){
        DEBUG_MSG("Destructor");
    }
    int getI() { return i_; }
    void setI(int i){ i_ = i; }
    void fn()
    {
        DEBUG_MSG("Do Something Here");
    }
private:
    int i_;
};

using sharedPtr = std::shared_ptr < Test >;


class Manager{
public:
    sharedPtr createTest(int i)
    {
        auto ptr = std::make_shared<Test>(i);
        list_.insert(ptr);
        return ptr;
    }

    void drop(sharedPtr ptr)
    {
        list_.erase(ptr);
    }

private:
    std::set<sharedPtr> list_;
};

int main()
{
    Manager mng;
    auto test = mng.createTest(50);
    DEBUG_MSG("test : " << test.use_count());
    test->fn();
    mng.drop(test);
    DEBUG_MSG("test : " << test.use_count());

    system("Pause");
    return 0;
}

可以看出:在我的代码中,当我调用mng.drop(test) - 仍然是the reference count is 1时,因此对象不会被破坏。

Test::Test                                                                 :  22   :    Constructor
main                                                                       :  62   :    test : 2
Test::fn                                                                   :  31   :    Do Something Here
main                                                                       :  65   :    test : 1
Press any key to continue . . .

修改

My requirement: Manager Class should hold shared_ptr to all Test instances active; It should able to create and destroy Test instance

3 个答案:

答案 0 :(得分:3)

createTest返回并存储在test中的指针与管理员管理的所有权共享;在两个对象都被删除之前,它不会被销毁。

createTest如果客户端应该访问对象而不共享所有权,则应返回weak_ptr。他们可以暂时锁定指针,以防止在需要访问时删除;虽然你必须相信他们不要永久锁定它,但如果经理因某种原因拥有这种“独特”的所有权真的很重要。

答案 1 :(得分:3)

您的要求没有意义。如果你需要直接控制对象&#39;生命周期,不要使用为间接控制明确设计的智能指针(std::shared_ptr)。无论如何,为什么你有这样的技术要求?尝试重新协商他们。

如果这不是一个选项,并且您愿意编写符合(不合逻辑)要求的代码,无论后果如何,您都可以这样做:

class Manager{
public:
    sharedPtr createTest(int i)
    {
        std::unique_ptr<Test> ptr(new Test(i));
        sharedPtr res(ptr.get(), [](Test*) {});
        list_.insert(std::move(ptr));
        return res;
    }

    void drop(sharedPtr ptr)
    {
        list_.erase(ptr.get()); // This requires C++14, or adapt list_ so that you can search by raw pointer in it
    }

private:
    std::set<std::unique_ptr<Test>> list_;
};

代码为共享指针提供no-op删除器。对象的生命周期由unique_ptr内的Manager管理,但客户端可以根据需要通过shared_ptr访问对象。是的,这个共享指针可以变成悬空,但这是要求中固有的。


如果shared_ptr使用的要求实际上是可以协商的,我会看到三种方法:

  1. Manager暂停unique_ptr<Test>并发出Test*(这些观察员都可以)。记录他们的生命周期由经理明确管理,如果持有时间过长,他们就会变得悬空。

  2. 关注@ MikeSeymour的回答,让Manager保持shared_ptr并发出weak_ptr s。记录Manager只能保证drop()如果客户的行为遭到破坏,并且不会永久锁定weak_ptr

  3. 发出类似于QPointer的智能指针,当对象被销毁时,它会被设置为null。

  4. 我更喜欢#1;对我来说,感觉是最简单的事情。作为观察者,原始指针非常精细,如果你有明确的生命周期管理,你总是冒险在某处晃动指针。所以只需记录好并接受它。

答案 2 :(得分:0)

auto test = mng.createTest(50);
// here the count should be 2 and not 1
// one by the list's member and one by test
DEBUG_MSG("test : " << test.use_count());
test->fn();
mng.drop(test);
DEBUG_MSG("test : " << test.use_count());
  当我调用mng.drop(test)时,在我的代码中

- 仍然引用计数为1,因此对象不会被破坏。

这是因为您仍然坚持test,当您致电mng.drop时,您会向其提供test的副本,从而将引用计数从n增加到n + 1.现在它完成所有操作,将引用计数减少2:一次用于局部变量ptr,一次用于列表中的一个,但是你持有的那个仍然存在。

您也要发布对它的引用

test.reset();

这应该使引用计数为0.您将能够看到析构函数消息被打印。