如何防止ptr_map插入失败时释放数据 [英] How to prevent ptr_map releasing data when it fails inserting

查看:50
本文介绍了如何防止ptr_map插入失败时释放数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题 插入或更新ptr_map 我想使用以下代码

In my question insert or update in ptr_map I wanted to use the following code

typedef boost::ptr_map<const std::string, Entry> KeyEntryMap;
KeyEntryMap m;
void insertOrUpate(const char* key, Entry* entry) {
    std::pair<KeyEntryMap::iterator, bool> re = m.insert(key, entry);
    if (!re.second) {
        m.replace(re.first, entry);
    }
}

但是,如果插入失败,则ptr_map插入中的以下代码(按auto_type)释放入口对象.

However, the following code from ptr_map insert releases (by auto_type) the entry object if an insert fails.

    std::pair<iterator,bool> insert_impl( const key_type& key, mapped_type x ) // strong
    {
        this->enforce_null_policy( x, "Null pointer in ptr_map_adapter::insert()" );
        auto_type ptr( x );                                         // nothrow

        std::pair<BOOST_DEDUCED_TYPENAME base_type::ptr_iterator,bool>
             res = this->base().insert( std::make_pair( key, x ) ); // strong, commit      
        if( res.second )                                            // nothrow     
            ptr.release();                                          // nothrow
        return std::make_pair( iterator( res.first ), res.second ); // nothrow        
    }

我猜这是因为ptr_map想要确保插入的ptr在这种情况下不会泄漏.这是否意味着在调用replace时我们必须创建一个新的入口对象?我们可以让ptr_map停止释放它吗?

I guess this is because ptr_map wants to ensure the ptr to insert is not leaked at the case. Does it mean we have to create a new entry object when calling replace? can we let ptr_map stop releasing it?

替代方法是先使用查找.

The alternative is using find first.

    KeyEntryMap::iterator p = m.find(key);
    if (p == m.end()) {
        m.insert(key, entry);
        return;
    }

    m.replace(p, entry);

这对于插入盒是否有更多成本?它需要两次搜索地图.

Does this have more cost for insert case? It needs searching the map twice.

推荐答案

是的.指针容器拥有您提供给它们的所有指针的所有权.

Yes that's expected. Pointer containers take ownership of all pointers you give to them.

同样,m.replace(...)释放地图中先前存在的元素,除非您捕获"它:

Likewise, m.replace(...) frees the element previously existing in the map unless you "catch" it:

KeyEntryMap::auto_type previous = m.replace(re.first, entry);

这是不变式/契约,导致代码很容易正确(面对异常情况,不会泄漏内存等)

It's an invariant/contract that leads to code that's easy to get right (in the face of exceptions, not leaking memory etc.)

如果您愿意允许可为null的映射类型,可以使用一个狡猾的小技巧:

One devious little trick you could use iff you are willing to allow nullable mapped-types:

typedef boost::ptr_map<const std::string, boost::nullable<Entry> > KeyEntryMap;

struct Demo {
    KeyEntryMap m;

    void insertOrUpate(const char* key, Entry* entry) {
        auto it = m.insert(key, nullptr).first;
        /*auto previous =*/ m.replace(it, entry);
    }
};

除此之外,获取插入点并进行检查:

Other than that, get the insertion point, and do the check:

void insertOrUpate(const char* key, Entry* entry) {
    auto range = m.equal_range(key);
    if (range.empty()) {
        m.insert(range.end(), key, entry);
    } else {
        m.replace(range.begin(), entry);
    }
}

这样,仍然只有一个查询.

This way, there's still only one query.

在Coliru上直播

#include <boost/ptr_container/ptr_map.hpp>
#include <string>

struct Entry {
    int id = [] { static int idgen = 0; return idgen++; }();
};

typedef boost::ptr_map<const std::string, Entry> KeyEntryMap;

struct Demo {
    KeyEntryMap m;

    void insertOrUpate(const char* key, Entry* entry) {
        auto range = m.equal_range(key);
        if (!range.empty()) {
            m.replace(range.begin(), entry);
        } else {
            m.insert(range.end(), key, entry);
        }
    }

    friend std::ostream& operator<<(std::ostream& os, Demo const& d) {
        for (auto e : d.m) os << e.first << ":" << e.second->id << " ";

        return os;
    }
};

#include <iostream> 

int main() {
    Demo d;
    for (auto key : { "a", "a", "c", "a", "b" }) {
        d.insertOrUpate(key, new Entry());
        std::cout << d << "\n";
    }
}

打印

a:0 
a:1 
a:1 c:2 
a:3 c:2 
a:3 b:4 c:2 

这篇关于如何防止ptr_map插入失败时释放数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆