飞道的博客

C++(标准库):25---STL容器之(实现容器reference语义)

423人阅读  评论(0)

一、C++标准库提供的是value语义

  • 通常,所有容器都会建立元素拷贝,返回的也是元素的拷贝
  • STL只支持value语义,不支持reference语义。优缺点如下:
    • 优点:
      • 复制元素很简单
      • 使用reference时容易出错,你必须确保reference所指对象仍然健在,并需要小心队服偶尔出现的环式指向状态
    • 缺点:
      • 复制元素可能会导致不良的效率,有时甚至无法复制
      • 无法在数个不同的容器中管理同一份对象
  • 实现reference语义的两种做法:
    • ①使用智能指针
    • ②使用reference_wrapper

二、使用Shared Pointer

  • C++标准库提供了许多智能指针。如果你打算在不同的容器之间共享对象,shared_ptr<>是一个适当的选择

演示案例

  • 创建了一个Item类和一个printItems()函数用来打印类的内容

   
  1. class Item {
  2. private:
  3. std:: string name;
  4. float price;
  5. public:
  6. Item( const std:: string& n, float p = 0) :name(n), price(p) {}
  7. std:: string getName()const { return name; }
  8. void setName(const std::string& n) { name = n; }
  9. float getPrice()const { return price; }
  10. void setPrice(float p) { price = p; }
  11. };
  12. template< typename Coll>
  13. void printItems(const std::string& msg, const Coll& coll)
  14. {
  15. std:: cout << msg << std:: endl;
  16. for ( const auto& elem : coll)
  17. {
  18. std:: cout << " " << elem->getName() << ":" << elem->getPrice() << std:: endl;
  19. }
  20. }
  • 测试程序如下:

   
  1. int main()
  2. {
  3. typedef std:: shared_ptr<Item> ItemPtr;
  4. std:: set<ItemPtr> allItems;
  5. std:: deque<ItemPtr> bestsellers;
  6. //为bestsellers添加元素
  7. bestsellers = { ItemPtr( new Item( "Kong Yize", 20.10)),
  8. ItemPtr( new Item( "A Midsummer Night's Dream", 14.99)),
  9. ItemPtr( new Item( "The Maltese Falcon", 9.88))
  10. };
  11. //为allItems添加元素
  12. allItems = { ItemPtr( new Item( "Water", 0.44)),
  13. ItemPtr( new Item( "Pizza", 2.22))
  14. };
  15. //将bestsellers内的所有元素添加进allItems
  16. allItems.insert(bestsellers.begin(), bestsellers.end());
  17. //打印一下bestsellers和allItems内的元素
  18. printItems( "bestsellers", bestsellers);
  19. printItems( "allItems", allItems);
  20. std:: cout << std:: endl;
  21. //遍历bestsellers,将其内部的每一个对象的price加倍
  22. for_each(bestsellers.begin(), bestsellers.end(),
  23. []( std:: shared_ptr<Item>& elem) {elem->setPrice(elem->getPrice() * 2);}
  24. );
  25. //将bestsellers[1]的元素更改为allItems内名为“Pizza”的元素
  26. bestsellers[ 1] = *(
  27. find_if(allItems.begin(), allItems.end(),
  28. []( std:: shared_ptr<Item> elem) { return elem->getName() == "Pizza"; })
  29. );
  30. //将bestsellers[0]对象的price设置为44.77
  31. bestsellers[ 0]->setPrice( 44.77);
  32. //打印一下bestsellers和allItems内的元素
  33. printItems( "bestsellers", bestsellers);
  34. printItems( "allItems", allItems);
  35. }
  • 使用智能指针为set<>和deque<>创建元素,其内的每个元素都是智能指针。后面对set<>和deque<>进行了一系列的操作,由于智能指针是共享的,因此改变一者,另一者也改变

  • 注意事项:使用shared_ptr<>会使事情变得复杂。例如,set<>容器内存储的是智能指针之后,不能再使用find()算法了,因此find()算法会找出拥有相等value的元素,现在比较的却是内部(由new返回)的pointer,因此只能使用find_if()算法

三、使用Reference Wrapper

  • reference_wrapper在之前的文章介绍过,参阅:https://blog.csdn.net/qq_41453285/article/details/105454812
  • reference_wrapper可以将传值调用改为传reference调用
  • 假设保证“只要容器存在,被指向的元素一定存在”,那就可以使用reference_wrapper。见下面的演示案例

演示案例

  • 此演示案例仍然使用到上面的Item类

   
  1. int main()
  2. {
  3. std:: vector< std::reference_wrapper<Item>> books;
  4. Item f("Faust", 12.99);
  5. books.push_back(f); //将f的引入传递给books,现在books内存放的是f的引用
  6. for ( const auto& book : books) {
  7. std:: cout << book.get().getName() << ": " << book.get().getPrice() << std:: endl;
  8. }
  9. //通过f改变内容
  10. f.setPrice( 9.99);
  11. std:: cout << books[ 0].get().getPrice() << std:: endl;
  12. //可以看到vector内的也改变了
  13. for ( const auto& book : books) {
  14. std:: cout << book.get().getName() << ": " << book.get().getPrice() << std:: endl;
  15. }
  16. }

  • 这种做法的优点是不需要pointer语法。然而这个也有风险,因此此处使用reference而非显然意见
  • 注意,下面的声明是不行的,因此其不是引用:


转载:https://blog.csdn.net/qq_41453285/article/details/105485576
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场