Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 销毁时从单一托管容器中删除对象_C++_Singleton_Shared Ptr - Fatal编程技术网

C++ 销毁时从单一托管容器中删除对象

C++ 销毁时从单一托管容器中删除对象,c++,singleton,shared-ptr,C++,Singleton,Shared Ptr,我有一个Singleton类,它管理Items的容器,公开允许从容器中添加或删除Items的公共函数 class Item; typedef std::shared_ptr<Item> ItemPtr; class Singleton { public: static Singleton& Instance() { static std::unique_ptr<Singleton> Instance(new Singleton); ret

我有一个
Singleton
类,它管理
Item
s的容器,公开允许从容器中添加或删除
Item
s的公共函数

class Item;
typedef std::shared_ptr<Item> ItemPtr;

class Singleton
{
public:
  static Singleton& Instance()
  {
    static std::unique_ptr<Singleton> Instance(new Singleton);
    return *Instance;
  }

  void Add(ItemPtr item)
  {
    mContainer.push_back(item);
  }

  void Remove(ItemPtr item)
  {
    for (auto it = mContainer.begin(); it != mContainer.end(); it++)
      if (*it == item)
        mContainer.erase(it);
  }

private:
  std::vector<ItemPtr> mContainer;
};
当我运行下面的示例时,我在
Singleton::Remove()
上遇到了一个崩溃,特别是
mContainer.begin()
上的
EXC\u BAD\u访问

这似乎表明
mContainer
不再存在。查看调用堆栈,我还可以看到根调用堆栈框架之一是析构函数
Singleton::~Singleton()
,这可以解释为什么
mContainer
不再存在

我尝试了另一种方法:我没有使用
std::shared_ptr
,而是使用原始指针(即
Item*
),并在代码中进行适当的替换。它毫无问题地工作

我的问题是:

  • 我猜现在发生的情况是,
    对象的所有权只有在销毁了
    单例
    后才由
    共享的ptr
    释放,这导致了错误。这是正确的吗
  • 如果
    Singleton
    中的容器是
    shared\u ptr
    ,是否不可能完成我想做的事情
  • 如果没有,我怎么做

尽管这样做首先是明智的,但是如果您愿意使用并且遵守std::enabled\u shared\u from\u this
的限制,您想要的东西是可以实现的。见下文:

#include <iostream>
#include <algorithm>
#include <memory>
#include <vector>

struct Item;
typedef std::shared_ptr<Item> ItemPtr;

class Singleton
{
private:
    Singleton() {}

public:
    static Singleton &Instance()
    {
        static Singleton s;
        return s;
    }

    void Add(ItemPtr item)
    {
        mContainer.emplace_back(std::move(item));
    }

    void Remove(const ItemPtr& item)
    {
        mContainer.erase(
            std::remove(mContainer.begin(), mContainer.end(), item), 
            mContainer.end());
    }

    void Clear()
    {
        mContainer.clear();
    }

private:
    std::vector<ItemPtr> mContainer;
};

// note derivation. this means you can get a std::shared_ptr<Item>
// via `shared_from_this` , but it also means the object itself
// MUST be an actual shared object to begin with.
struct Item : public std::enable_shared_from_this<Item>
{
    void Add()
    {
        Singleton::Instance().Add(shared_from_this());
    }
};


int main()
{
    ItemPtr a = std::make_shared<Item>();
    ItemPtr b = std::make_shared<Item>();

    // add to the singleton container
    a->Add();
    b->Add();

    // report reference count of 'a'
    std::cout << "before removal 'a' has " << a.use_count() << " references\n";
    Singleton::Instance().Remove(a);
    std::cout << "after removal 'a' has " << a.use_count() << " references\n";
}
其中最重要的部分是在
main
中创建
a
b
。请注意,它们实际上是由
std::shared\u ptr
从一开始就隐藏起来的。这是使该中的_共享_正常工作所必需的。其余的则相当直截了当。通过基类
std::enable_shared_from_this
提供的
shared_from_this()
成员,可以从
项的任何成员体中获取引用bumped
std::shared_ptr


简而言之,采用这种方法对您有效,但在任何情况下都不能使用
shared\u from\u this()
,除非它所触发的对象首先已经由
std::shared\u ptr
管理。记住这一点。

在顶部,
Singleton::Remove
表现出未定义的行为
mContainer.erase(它)
使
it
无效,然后
it++
访问这个现在无效的迭代器。您可能正在查找
ItemPtr(this)
是个坏主意,因为它会导致双重破坏:
ItemPtr
temporary在分号处被破坏,并将在
this
上调用
delete
。原始指针
a
b
隐藏在推到容器中的
std::shared\u ptr
实例中。那些赤裸裸的
delete
调用是错误的。动态对象要么由智能指针管理,要么不是。你不可能两全其美,当然你也不可能让他们最终毁灭两次。您绝对应该从_this
中查看启用的_shared _,并记住,如果您选择该路径,则任何生成
std::shared _ptr
的实例请求都必须从初始创建时就进行管理。由于该对象在单例中始终处于活动状态,因此该对象将如何被销毁?这有点循环。
int main()
{
  Item* a = new Item();
  Item* b = new Item();

  a->Add();
  b->Add();

  delete a;
  delete b;
}
#include <iostream>
#include <algorithm>
#include <memory>
#include <vector>

struct Item;
typedef std::shared_ptr<Item> ItemPtr;

class Singleton
{
private:
    Singleton() {}

public:
    static Singleton &Instance()
    {
        static Singleton s;
        return s;
    }

    void Add(ItemPtr item)
    {
        mContainer.emplace_back(std::move(item));
    }

    void Remove(const ItemPtr& item)
    {
        mContainer.erase(
            std::remove(mContainer.begin(), mContainer.end(), item), 
            mContainer.end());
    }

    void Clear()
    {
        mContainer.clear();
    }

private:
    std::vector<ItemPtr> mContainer;
};

// note derivation. this means you can get a std::shared_ptr<Item>
// via `shared_from_this` , but it also means the object itself
// MUST be an actual shared object to begin with.
struct Item : public std::enable_shared_from_this<Item>
{
    void Add()
    {
        Singleton::Instance().Add(shared_from_this());
    }
};


int main()
{
    ItemPtr a = std::make_shared<Item>();
    ItemPtr b = std::make_shared<Item>();

    // add to the singleton container
    a->Add();
    b->Add();

    // report reference count of 'a'
    std::cout << "before removal 'a' has " << a.use_count() << " references\n";
    Singleton::Instance().Remove(a);
    std::cout << "after removal 'a' has " << a.use_count() << " references\n";
}
before removal 'a' has 2 references
after removal 'a' has 1 references