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++STLC++
- c++stl notesC++
- 兩種方式實現輪播圖
- SpringBoot實現熱部署兩種方式!Spring Boot熱部署
- 前端--實現隔行變色的兩種方式前端
- React元件方法的兩種定義方式React元件
- C++STL常見面試題C++面試題
- C++STL學習第一篇(什麼是STL以及string的各種功能用法)C++
- Spring宣告式事務的兩種實現方式Spring
- zuul實現Cors跨域的兩種方式(https)ZuulCORS跨域HTTP
- MyBatis中主鍵回填的兩種實現方式MyBatis
- 以 ZGC 為例,談一談 JVM 是如何實現 Reference 語義的GCJVM
- C++STL第二篇(vector的原理用法)C++
- 兩種方式實現橫向滾動條
- ViewPager兩種方式實現無限輪播Viewpager
- 關於多執行緒的兩種實現方式執行緒
- css實現圖片自適應容器的幾種方式CSS
- 易語言執行js的兩種方式JS
- SSH整合實現分頁查詢(兩種方式)
- Java中實現並行請求兩種方式Java並行
- Spring Boot 中實現定時任務的兩種方式Spring Boot
- ABAP 程式語言裡的 Reference Semantic - 引用語義
- 基於 Electron 做視訊會議的兩種實現方式
- html隨意拖動內容位置的兩種實現方式HTML
- STL————deque容器
- STL容器---Vector
- springAOP的三種實現方式Spring
- ChatTTS的兩種使用方式TTS
- C++STL第四篇(最簡單的棧和佇列)C++佇列
- C++STL第五篇(連結串列List的使用方法)C++
- Java兩種方式實現連結串列的刪除,返回頭結點Java
- 雜湊表的兩種實現
- 實現 JavaScript 沙箱的幾種方式JavaScript
- STL常用序列容器
- STL容器之deque
- STL使用篇__容器
- STL_string容器
- STL_deque容器