首页 > 编程语言 >C++ STL容器的Value语义与Reference语义

C++ STL容器的Value语义与Reference语义

时间:2023-01-12 23:56:00浏览次数:45  
标签:容器 Reference STL bestsellers 元素 语义 allItems Item

C++ STL容器的Value语义与Reference语义

1.Value语义vs.Reference语义

1.1两种语义简述

​ 通常情况下,所有容器都是建立元素的copy,返回的元素的copy。因此,容器内的元素与我们放进去的元素虽然equal但是并不非identical。如果修改容器的元素,实际上并没有修改原件对象。这就是STL容器所提供的$value$ 语义。然而在现实中,我们有时候需要将原件对象放入容器,而不是它的copy,这是我们就需要$Reference$语义,让容器容纳元素的reference。

1.2两种语义对比

  1. $Value$语义
    • 优点
      • 复制元素操作很简单;
    • 缺点
      • 复制元素效率可能很低,有时甚至无法复制;
      • 无法在数个不同的容器中管理同一份对象,即处在不同容器中同一个原件对象的copy没有联系。
  2. $Reference$
    • 优点
      • 复制元素效率高;
      • 可以在不同容器中管理同一份对象;
    • 缺点
      • 使用和管理相对复杂

2.实现Reference语义

​ 最先想到的方法是以pointer作为元素。不过寻常的pointer存在一些问题,可能出现野指针导致不确定情况,另外,pointer之间的比较行为可能常常不是我们所期待的,我们希望比较的是pointer所指的对象而不是pointer本身,所以需要在管理时付出很大的心血,非常谨慎,否则就会进入不确定情况的泥潭。

​ 相对更好的方法是使用smart poniter,这是一种对象,有着类似pointer的接口,但内部做了额外的检查和处理,便于管理;另一种方式是使用$class std::reference_wrapper<>$,让STL容器持有reference。

2.1使用$shared_ptr$智能指针

  • 举例说明
#include <iostream>
#include <string>
#include <set>
#include <algorithm>
#include <deque>
#include <memory>
using namespace std;

class Item {
private:
	string name;
	float price;
public:
	Item(const string& n, float p = 0) : name(n), price(p) {

	}

	string getName() const {
		return name;
	}

	void setName(string& n) {
		name = n;
	}

	float getPrice() const {
		return price;
	}

	void setPrice(float p) {
		price = p;
	}
};


template <typename T>
void printItems(const std::string& msg, const T& coll) {
	cout << msg << endl;
	for (const auto& elem : coll) {
		cout << ' ' << elem->getName() << ':' << elem->getPrice() << endl;
	}
}

int main()
{
	typedef shared_ptr<Item> ItemPtr;
	set<ItemPtr> allItems;
	deque<ItemPtr> bestsellers;

	bestsellers = { ItemPtr(new Item("Apple", 5.20)),
					ItemPtr(new Item("Banana", 3.21)),
					ItemPtr(new Item("Cake", 10.24)) };
	allItems = { ItemPtr(new Item("Pizza", 2.22)),
				 ItemPtr(new Item("People", 0.01)) };
	//将bestsellers中的项目插入allItems中,并且对于apple,banana,cake两者应该指向同一个对象.
	allItems.insert(bestsellers.begin(), bestsellers.end());

	//print1
	printItems("bestsellers1:", bestsellers);
	printItems("allItems1:", allItems);
	cout << endl;

	//double price of bestsellers --> allItems中相应的元素也会改变
	for_each(bestsellers.begin(), bestsellers.end(),
		[](shared_ptr<Item>& elem) {
			elem->setPrice(elem->getPrice() * 2);
		});
	//Banana <--> Pizza
	bestsellers[1] = *(find_if(allItems.begin(), allItems.end(),
		[](shared_ptr<Item> elem) {
			return elem->getName() == "Pizza";
		}));
	//set price
	bestsellers[0]->setPrice(100000.2);

	//print2
	printItems("bestsellers2:", bestsellers);
	printItems("allItems2:", allItems);
	cout << endl;

	return 0;
}

运行结果

  • 评价

    如果打算在不同的容器之间共享对象,shared_ptr是合适的选择。不过,使用它也可会让事情变复杂,例如,面对set使用find(),会找出相等value的元素,现在比较的是内部的pointer.所以我们需要使用find_if算法。

    allItems.find(ItemPtr(new Item("Pizza", 2.22)))  //failed
    

2.2使用$class std::reference_wrapper<>$

  • 举例说明
vector<reference_wrapper<Item>> books;  //它的元素是reference

	Item f("STL Standard", 20.1);
	books.push_back(f);

	cout << books[0].get().getName() << ' ' << books[0].get().getPrice() << endl; //get是必要的

	f.setPrice(9.99);
	cout << books[0].get().getPrice() << endl;
	cout << f.getPrice() << endl;

  • 评价

假设“只要容器存在,被指向的元素一定存在”,我们就可以使用这种方法。这种方法的优点是不需要pointer语法,然而这也是一共风险,因为此处使用reference并非显而易见。下面的声明不可行。

vector<Item&> books;

标签:容器,Reference,STL,bestsellers,元素,语义,allItems,Item
From: https://www.cnblogs.com/yxdong/p/17048289.html

相关文章

  • LeetCode报错:Line 923: Char 9: runtime error: reference binding to null pointer o
    LeetCode报错报错原因:Line923:Char9:runtimeerror:referencebindingtonullpointeroftype‘std::__cxx11::basic_string<char,std::char_traits,std::alloca......
  • JSTL
    1.概念:JavaServerPageTagLibraryJSP标准标签库  *是由apache组织提供的开源的免费的jsp标签2.作用:用于简化和替换jsp页面上的java代码3.使用步骤:  1.导入jstl......
  • C++ STL的简单应用(vector容器专题)
    #include<iostream>#include<string>#include<stdlib.h>#include<vector>//#include<algorithm>usingnamespacestd;//vector容器的简单应用voiddemo1(){......
  • 前端知识点整理第二天(伪类和伪元素/html5语义化)
    SEO,也就是搜索引擎优化的逻辑,其实是非常简单的。这就像是在大学里的学生会主席,你要让投票者给你更多的选票。那么,你需要先「自我优化」,无论是外表还是能力;此外,你还需获得......
  • STL关联式容器使用注意、概念总结
    引入继上文STL序列式容器使用注意、概念总结继续总结关联式容器的概念以及一些使用事项。关联式容器与容器适配器基础容器STL中的关联式底层容器:RBtree,hashtabl......
  • C++ STL摘记
    一、string类补充1.函数示例:(1)find和rfind函数,返回的是下标或者string::nposindex=ss.find(s1,pos,num)find从pos(包括)开始往右查找(num的作用待补充)index=s......
  • 树莓派raspberry编译isc-dhcp遇到“undefined reference to `__atomic_fetch_add_8'”
    想在树莓派上修改dhclient,增加一些打印信息,需要编译isc-dhcp。但是在编译过程中遇到了一个错误,错误如下:1gcc-g-Wall-Werror-fno-strict-aliasing-I../includes......
  • Docker搭建测试用例平台 TestLink
    Testlink是基于WEB的测试用例管理系统,主要功能是:测试项目管理、产品需求管理、测试用例管理、测试计划管理、测试用例的创建、管理和执行,并且还提供了统计功能。Testlink......
  • JSTL fn函数使用
    首先,我们要在页面的最上方引用:<%@taglibprefix="fn"uri="http://java.sun.com/jsp/jstl/functions"%>下面是JSTL中自带的方法列表以及其描述:fn:contains(string,subs......
  • jstl
    一. MVC模型(Model)-程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。视图(View)-界面设计人员进行图形界面设计。......