在我的问题中 insert or update in ptr_map 我想使用以下代码
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)条目对象。
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停止释放吗?
另一种方法是首先使用find。
KeyEntryMap::iterator p = m.find(key);
if (p == m.end()) {
m.insert(key, entry);
return;
}
m.replace(p, entry);
这是否会增加插入案例的成本?它需要两次搜索地图。
答案 0 :(得分:1)
是的,这是预料之中的。指针容器取得你给它们的所有指针的所有权。
同样地,m.replace(...)
释放先前存在于地图中的元素,除非你&#34; catch&#34;它:
KeyEntryMap::auto_type previous = m.replace(re.first, entry);
它是一个不变/合同,导致代码很容易正确(面对异常,而不是泄漏内存等)。
如果你愿意允许可以为空的映射类型,你可以使用一个狡猾的小技巧:
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);
}
};
除此之外,获取插入点,并进行检查:
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);
}
}
这样,仍然只有一个查询。
<强> Live On 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