因此,這裏是另一個選項,基於通過移動std::unique_ptr<>
來導入對象。不幸的是,unique_ptr
對於std::set
(因爲它們是唯一的)並不是有用的鍵,除非你有C++ 14,否則當set::find()
可以採用另一個參數而不是一個鍵(見下文)時。
對於C++ 11方法,必須使用因此std::map
存儲unique_ptr
s,這需要加倍id
和name
條目:一旦在data_t
,一次作爲在map
S]鍵。這是一張草圖。
struct data_t {
const std::size_t id; // changing these would
const std::string name; // lead to confusion
/* more data */
};
using data_ptr = std::unique_ptr<data_t>;
using data_map = std::map<std::size_t,data_ptr>;
using obj_it = data_map::iterator;
using name_map = std::multimap<std::string,obj_it>;
data_map DataSet;
name_map NameMap;
std::vector<data_t*> find_by_name(std::string const&name) const
{
auto range = NameMap.equal_range(name);
std::vector<data_t*> result;
result.reserve(std::distance(range.first,range.second));
for(auto it=range.first; it!=range.second; ++it)
result.push_back(it->second->get());
return result;
}
data_t* find_by_id(std::size_t id) const
{
auto it = DataSet.find(id);
return it == DataSet.end()? nullptr : it->second.get();
}
// transfer ownership here
void insert_object(data_ptr&&ptr)
{
const auto id = ptr->id;
if(DataSet.count(id))
throw std::runtime_error("id '"+std::to_string(id)+"' already known");
auto itb = DataSet.emplace(id,std::move(ptr));
auto err = itb.second;
if(!err)
err = NameMap.emplace(itb.first->name,itb.first).second;
if(err)
throw std::runtime_error("couldn't insert id "+std::to_string(id));
}
// remove object given an observing pointer; invalidates ptr
void delete_object(data_t*ptr)
{
if(ptr==nullptr)
return; // issue warning or throw ?
auto it = DataSet.find(ptr->id);
if(it==DataSet.end())
throw std::runtime_error("attempt to delete an unknown object");
auto range = NameMap.equal_range(it->second->name);
for(auto i=range.first; i!=range.second; ++i)
if(i->second==it) {
NameMap.erase(i);
break;
}
DataSet.erase(it);
}
這裏爲C++ 14溶液,這避免了在地圖中的id
和name
數據的重複的草圖,但需要/假定data_t::id
和data_t::name
是不變的。
struct data_t {
const std::size_t id; // used as key in set & multiset:
const std::string name; // must never be changed
/* more data */
};
using data_ptr = std::unique_ptr<data_t>;
struct compare_id {
using is_transparent = std::size_t;
static bool operator(data_ptr const&l, data_ptr const&r)
{ return l->id < r->id; }
static bool operator(data_ptr const&l, std::size_t r)
{ return l->id < r; }
static bool operator(std::size_t l, data_ptr const&r)
{ return l < r->id; }
};
using data_set = std::set<data_ptr,compare_id>;
using data_it = data_set::const_iterator;
struct compare_name {
using is_transparent = std::string;
static bool operator(data_it l, data_it r)
{ return (*l)->name < (*r)->name; }
static bool operator(data_it l, std::string const&r)
{ return (*l)->name < r; }
static bool operator(std::string const&l, data_it r)
{ return l < (*r)->name; }
};
using name_set = std::multiset<data_it,compare_name>;
data_set DataSet;
name_set NameSet;
std::vector<data_t*> find_by_name(std::string const&name) const
{
auto range = NameSet.equal_range(name);
std::vector<data_t*> result;
result.reserve(std::distance(range.first,range.second));
for(auto it=range.first; it!=range.second; ++it)
result.push_back((*it)->get());
return result;
}
data_t* find_by_id(std::size_t id) const
{
auto it = DataSet.find(id);
return it == DataSet.end()? nullptr : it->get();
}
// transfer ownership here
void insert_object(data_ptr&&ptr)
{
const auto id = ptr->id;
if(DataSet.count(id))
throw std::runtime_error("id '"+std::to_string(id)+"' already known");
auto itb = DataSet.emplace(std::move(ptr));
auto err = itb.second;
if(!err)
err = NameSet.emplace(itb.first).second;
if(err)
throw std::runtime_error("couldn't insert id "+std::to_string(id));
}
// remove object given an observing pointer; invalidates ptr
void delete_object(data_t*ptr)
{
if(ptr==nullptr)
return; // issue warning or throw ?
auto it = DataSet.find(ptr->id);
if(it==DataSet.end())
throw std::runtime_error("attempt to delete an unknown object");
auto range = NameSet.equal_range(ptr->name);
for(auto i=range.first; i!=range.second; ++i)
if((*i)==it) {
NameSet.erase(i);
break;
}
DataSet.erase(it);
}
有可能是在這裏的一些錯誤,特別是與錯誤提領該迭代器的各種指針和類型(儘管一旦它編譯這些應該沒問題)。
爲什麼你甚至想手動刪除一個'shared_ptr'持有的對象?這就違背了使用'shared_ptr'的目的。 – UnholySheep
如何從vector中移除'shared_pr'?這裏沒有魔法 - 從vector中移除'shared_ptr'會調用它的析構函數(除非通過移動來移除)。如果沒有任何其他'shared_ptr'實例持有引用對象的ref-count,'shared_ptr'的析構函數將自動釋放Object的實例的內存。記得在事後正確檢查'std :: weak_ptr :: lock()'的成功,即檢查結果是否爲'nullptr',或者同時移除地圖中的'weak_ptr's。 – thokra
從向量中刪除意味着我必須遍歷向量才能找到並刪除它。這違背了索引的目的。請注意我不想理解smart_ptr/weak_ptr的工作情況。有沒有什麼辦法可以重置()vector上的smart_ptr,而無需迭代它?我只有一個weak_ptr對象。 – Sharath