C++STL::兩種方式實現STL容器的reference語義
STL容器提供的是“value semantic”而非“reference semantic”。然而不論是為了降低元素過大的複製代價還是為了在不同集合中共用同一個元素的需求,這時我們必須使用“reference semantic”,方式有二:
使用智慧指標
#include <string>
#include <iostream>
#include <memory>
#include <set>
#include <deque>
#include <algorithm>
class Item
{
private:
std::string _name;
float _price;
public:
Item(const std::string& name, float price):
_name(name), _price(price){}
std::string getName() const { return _name;}
void setName(const std::string& name) { _name = name;}
float getPrice() const { return _price;}
void setPrice(float price) { _price = price;}
};
template<typename Coll>
void printItems(const std::string& msg, const Coll& coll)
{
std::cout << msg << std::endl;
for (const auto& elem: coll)
std::cout << " " << elem->getName() << ": " << elem->getPrice() << std::endl;
}
int main(int, char**)
{
typedef std::shared_ptr<Item> ItemPtr;
std::set<ItemPtr> allItems;
std::deque<ItemPtr> bestItems;
bestItems = {ItemPtr(new Item("C++", 10.)), ItemPtr(new Item("Python", 20.))};
allItems = {ItemPtr(new Item("Machine Learning", 30.))};
allItems.insert(bestItems.begin(), bestItems.end());
// 此時bestItems同時被兩個容器所操縱
// 而我們知道兩種容器的更新應當是同步的
printItems("bestItems: ", bestItems);
printItems("allItems: ", allItems);
std::cout << std::endl;
// 將bestItems的售價都提高一倍
std::for_each(bestItems.begin(), bestItems.end(),
[](ItemPtr& elem){elem->setPrice(elem->getPrice()*2);});
// 同時修改allItems,bestItems
// 將bestItems[1]替換為“Machine Learning”
bestItems[1] = *std::find_if(allItems.begin(), allItems.end(),
[](ItemPtr elem){return elem->getName() == "Machine Learning";});
bestItems[0]->setPrice(55.);
printItems("bestItems: ", bestItems);
printItems("allItems: ", allItems);
return 0;
}
這裡尤其注意一個隱蔽的細節:
對bestItems[1]進行替換時,使用set的find成員函式還是使用std::find()都無法實現需求,如:
find(allItems.begin(), allItems.end(), ItemPtr(new Item("Machine Learning", 30.)));
allItems.find(ItemPtr(nwe Item("Machine Learning", 30.)));
因為將allItems的內部元素和傳遞進來的new出來的智慧指標作比較,是永遠不會相等的,所以最終返回的Iterator是allItems.end(),無法提領其元素。
這裡會存在一個問題,此時將bestItems銷燬時,allItems中的相應元素不會被銷燬,而會持續有效。
bestItems.clear();
printItems("allItems: ", allItems);
使用reference wrapper
假設保證“只要容器存在,被指向的元素一定存在”,就需使用另一種方法使用class reference_wrapper<>(位於<functional>標頭檔案)。
typedef std::reference_wrapper<Item> ItemRef;
std::vector<ItemRef> books;
// std::vector<Item&>,不允許
Item item1("C++", 20.);
books.push_back(item1);
for (const auto& book: books)
std::cout << book.get().getName() << ": " << book.get().getPrice() << std::endl;
// 當宣告其具體型別時,get()就不再必須
for (const Item& book: books)
std::cout << book.getName() << ": " << book.getPrice() << std::endl;
book.setPrice(29.99);
std::cout << books[0].get().getPrice() << std::endl;
// 29.99
books[0].get().setName("C++ Primer");
std::cout << books[0].get().getName() << std::endl;
// C++ Primer
相關文章
- Spring實現IOC容器的兩種實現方式Spring
- 點乘和叉乘及其物理意義(C++STL實現)點乘C++
- c++stl notesC++
- stl中各種容器的自定義比較函式函式
- 兩種方式實現輪播圖
- 前端--實現隔行變色的兩種方式前端
- C++STL常見面試題C++面試題
- React元件方法的兩種定義方式React元件
- wpf兩種佔位符實現方式
- 兩種方式實現web html sliderWebHTMLIDE
- 兩種遞迴方式實現迴文字遞迴
- MyBatis中主鍵回填的兩種實現方式MyBatis
- Spring定時器的兩種實現方式Spring定時器
- ViewPager兩種方式實現無限輪播Viewpager
- SpringBoot實現熱部署兩種方式!Spring Boot熱部署
- 兩種方式實現橫向滾動條
- css實現圖片自適應容器的幾種方式CSS
- zuul實現Cors跨域的兩種方式(https)ZuulCORS跨域HTTP
- Spring宣告式事務的兩種實現方式Spring
- 關於多執行緒的兩種實現方式執行緒
- C++STL學習第一篇(什麼是STL以及string的各種功能用法)C++
- C++STL第二篇(vector的原理用法)C++
- C#轉義字元的兩種處理方式C#字元
- 易語言執行js的兩種方式JS
- SSH整合實現分頁查詢(兩種方式)
- Java中實現並行請求兩種方式Java並行
- Android 頁面跳轉動畫的兩種實現方式Android動畫
- url跳轉的兩種實現方式 域名 80埠占用
- 請教兩種Singleton Pattern 實現方式的區別!
- Javascript中兩種方式定義函式的區別JavaScript函式
- html隨意拖動內容位置的兩種實現方式HTML
- Spring Boot 中實現定時任務的兩種方式Spring Boot
- 基於 Electron 做視訊會議的兩種實現方式
- GCD底層實現理解以及建立單例的兩種方式GC單例
- ABAP 程式語言裡的 Reference Semantic - 引用語義
- STL——STL中vector的實現原理
- C++實踐:STL容器reserveC++
- 【Python】python 多執行緒兩種實現方式Python執行緒