如何防止ptr_map插入失败时释放数据 [英] How to prevent ptr_map releasing data when it fails inserting
问题描述
我的问题 插入或更新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.
#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屋!