【发布时间】:2014-07-24 07:55:51
【问题描述】:
我正在为我的应用程序设计一个类,它实现了许多标准共享指针和标准容器的使用,例如 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...
}
函数中多写一行。
真的需要这样输入吗?为什么?
【问题讨论】:
-
您知道您使用的
std::map::insert重载正在返回一个std::pair,其中包含指向刚刚插入的元素的迭代器?这意味着您不需要find电话。返回的std::pair还包括一个布尔指示符,它告诉您插入是否正常,您不检查某些内容(如果find调用返回end()怎么办?)。 -
“根据这个网站...” - 该网站上的哪个特定声明与您有关(并且没有通过“上述异常安全问题也可以通过使用 [the] @ 来消除987654333@...")?
-
在地图上插入,所有 stl 容器 AFAIK 都使用复制值语义,所以应该没问题
-
auto iter = m_drag.insert(std::make_pair(drag.id, pointer)).first;但是您可能还想测试second(哦,这两者的名字多么糟糕),看看您是否真的插入了一些东西。 -
std::make_shared<Drag>(this)=> 失败。您需要enable_shared_from_this凭空创建共享指针。