C++ 在std::map中插入临时std::shared_ptr,是否有问题?

C++ 在std::map中插入临时std::shared_ptr,是否有问题?,c++,c++11,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; inlin

我正在为我的应用程序设计一个类,它实现了许多标准的共享指针和标准容器的使用,如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();
struct拖动;
标准::地图m_拖动;
typedef sigc::信号\u bet;
内联信号\下注信号\右\上();
这里是使用上述声明的函数之一,以及一个临时共享的ptr,它不仅要在这个函数中使用,而且要一直使用到很晚。这意味着函数返回后,共享指针应该仍然处于活动状态,因为它将在某个点被分配给另一个共享\u 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();
}
void Table::Field::在左上方(拖放)
{
m_drag.insert(std::make_pair(drag.id,std::make_shared(this));//this!
auto iter=m_drag.find(drag.id);
*iter->秒=阻力;
iter->second->cx=0-iter->second->tx;
iter->second->cy=0-iter->second->ty;
使窗口无效();
}
上述函数首先插入一个新的共享_ptr,然后将值从一个对象分配到另一个对象

我需要从您的回答中了解,在地图中插入临时共享ptr是否安全,并确保它不会是一个悬空或任何坏事

根据网站的说法,上述功能并不安全,因为这样写会更好:

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...
 }
void Table::Field::在左上方(拖放)
{
std::shared_ptr pointer=std::make_shared(这个);
m_drag.insert(std::make_pair(drag.id,指针));
auto iter=m_drag.find(drag.id);
*iter->秒=阻力;
//等等。。。
}
函数中还有一行


确实需要这样键入吗?为什么?

这两个函数在
std::shared\u ptr
方面没有区别,因为
std::make\u pair
函数将在临时对象销毁之前创建临时对象的副本。该副本将依次被复制到
std::map
,然后其自身将被销毁,在映射中留下一个副本。但由于另外两个对象已被破坏,因此贴图中该对象的引用计数仍将为1


对于处理
insert
的返回值,非常简单:

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

auto iter = result.first;

...
auto result=m_drag.insert(…);
如果(!result.second)
{

std::cerr示例中的代码与您的示例代码不同,因为它使用new操作符而不是
std::make_shared
。他们建议的关键部分如下:

由于函数参数是按未指定的顺序求值的,因此可以先求值
new int(2)
,然后求值
g()
,如果
g
抛出异常,我们可能永远无法找到
shared\u ptr
构造函数


std::make_shared
消除了这个问题-在
std::make_shared
中构造对象时分配的任何动态内存,如果有任何抛出,都将被取消分配。在这种情况下,您不必担心临时
std::shared_ptr
air
包含一个到刚刚插入的元素的迭代器?这意味着您不需要
find
调用。返回的
std::pair
还包含一个布尔指示符,它告诉您插入是否正常,一些您没有检查的内容(如果
find
调用返回
end()
?)。“根据本网站…”-该网站上的哪项具体声明与您有关(且“上述异常安全问题也可通过使用[The]
make_shared
…]消除”)?在地图上插入,并且AFAIK的所有stl容器都使用复制值语义,因此应该可以
auto-iter=m_drag.insert(std::make_pair(drag.id,pointer))。首先;
但您可能还想测试
第二个
(哦,这两个名字有什么不好的地方),看看您是否真的插入了内容。
std::make_shared(这个)
=>失败。你需要凭空创建一个共享指针。另一方面……如果对象是可复制的,为什么还要麻烦动态分配和
std::make_shared
。(如果目的是支持多态性,那么
std::make_shared
,或者甚至显式的
new
都不会削减多态性;您需要提供克隆功能。)@James我之所以将其共享,是因为该对象是在另一个返回指针的函数中创建的,所以我将其设置为有效。@codekiddy,只是您正在复制该对象,所以没有意义。(您确实需要一些东西来管理调用另一个函数的内存。为什么创建函数返回指针而不是对象?动态分配只会使代码变慢,并增加出错的机会。)