将临时std :: shared_ptr插入std :: map,不好吗?

时间:2014-07-24 07:55:51

标签: c++ c++11

我为我的应用程序设计了一个类,它实现了许多标准的共享指针和标准容器的使用,例如 std :: map std :: vector

这个问题是非常具体的问题所以我只是复制了一段代码 从我的标题为澄清目的.. 这是标题中声明的快照:

struct Drag;
std::map<short, std::shared_ptr<Drag>> m_drag;
typedef sigc::signal<void, Drag&> signal_bet;
inline signal_bet signal_right_top();

这是使用上述声明的函数之一和临时的shared_ptr,它不仅用于此函数,而且用于某个较晚的时间。这意味着在函数返回之后,共享指针应该仍然存在,因为它将在某个时刻被分配给另一个shared_ptr。

void Table::Field::on_signal_left_top(Drag& drag)
{
    m_drag.insert(std::make_pair(drag.id, std::make_shared<Drag>(this))); // THIS!
    auto iter = m_drag.find(drag.id);
    *iter->second = drag;
    iter->second->cx = 0 - iter->second->tx;
    iter->second->cy = 0 - iter->second->ty;

    invalidate_window();
}

上面的函数首先插入一个新的shared_ptr,然后将一个对象的值分配给另一个对象,

我的回答是,我要告诉你是否可以将临时的shared_ptr插入地图,并确保它不会是悬空或什么是坏事。

根据THIS网站,上述功能不被认为是安全的,因为写它会更好:

void Table::Field::on_signal_left_top(Drag& drag)
{
    std::shared_ptr pointer = std::make_shared<Drag>(this);
    m_drag.insert(std::make_pair(drag.id, pointer));
    auto iter = m_drag.find(drag.id);
    *iter->second = drag;
    // etc...
 }

在函数中多了一行。

是否真的需要输入它,为什么?

2 个答案:

答案 0 :(得分:8)

关于std::shared_ptr,两个函数之间没有区别,因为std::make_pair函数将在临时对象被销毁之前创建临时对象的副本。该副本将被复制到std::map中,然后本身将被破坏,从而在地图中留下副本副本。但由于其他两个对象已被破坏,因此地图中对象的引用计数仍为一。


至于处理来自insert的返回值,它非常简单:

auto result = m_drag.insert(...);
if (!result.second)
{
    std::cerr << "Could not insert value\n";
    return;
}

auto iter = result.first;

...

答案 1 :(得分:4)

给出的示例中的代码与示例代码不同,因为它使用 new 运算符而不是std::make_shared。他们建议的关键部分是:

  

由于函数参数是以未指定的顺序计算的,因此可能首先计算new int(2),g()second,如果g抛出异常,我们可能永远不会访问shared_ptr构造函数。

std :: make_shared消除了这个问题 - 在std :: make_shared中构造对象时分配的任何动态内存都会在抛出任何内容时被解除分配。在这种情况下,您不必担心临时的std :: shared_ptrs。