文档章节

c++ map 容器不存放指针

YLME
 YLME
发布于 2016/11/19 22:13
字数 784
阅读 538
收藏 0
c++

阿里云携手百名商业领袖、技术大咖,带您一探行进中的数字新基建!>>>

我对 c++ 容器的使用印象就是容器中最好存对象的指针,不要直接存放对象。看下面的代码片段,最好用 vec1 ,而 vec2 在添加对象到容器中时,会多一次复制。

struct container {
	int a;
	int b;
};
std::vector<container*> vec1;
std::vector<container> vec2;

所以我潜意识就是存放指针,不要直接存放对象。然后在实际开发中,有些不那么重要能满足需求的功能要是能采用更简洁的代码来实现,那就是太好了。上例中 vec1 在释放内存时还需要遍历 vector 释放元素指向的对象,而 vec2 则不必,代码就简洁一部分。

我在看 opengl 代码时看见一个例子。opengl 可以调用 glDrawArrays 绘制,也可以调用 glDrawElements 绘制,前者直接传入顶点数组数据。后者传入的是索引,若有相同的顶点数据则它们的索引是相同的,就有不必传送相同数据的效果。我看见的代码就是如何从一坨顶点数据中找到相同的顶点数据,并生成一个索引数组。举个例子若有 4 个顶点,坐标分别为 (0, 0, 0), (1, 1, 1), (0, 0, 0), (2, 2, 2) 。使用索引时顶点数据就简化成 (0, 0, 0), (1, 1, 1), (2, 2, 2) 而顶点索引数据则是 {0, 1, 2, 0} 。简单来说就是找出相同的顶点数据。

下面把那个 opengl 例子简化了,只关注如何找出相同的顶点数据。具体代码如下。

#include <cstdio>
#include <cstring>
#include <map>
#include <string>
#include <vector>

struct vec3 {
	float x;
	float y;
	float z;
};

struct vec2 {
	float x;
	float y;
};

struct PackedVertex {
	vec3 position;
	vec2 uv;
	
	// 最妙的地方。
	bool 
	operator<(const PackedVertex that) const {
		return memcmp((void*)this, (void*)&that, sizeof(PackedVertex)) > 0;
	}

	std::string
	str() const {
		char buff[100];
		snprintf(buff, 100, "(%f,%f,%f)(%f,%f)", position.x, position.y, position.z, uv.x, uv.y);
		std::string str(buff);
		return str;
	}
};

short 
get_index( 
	PackedVertex &packed, 
	std::map<PackedVertex, short> &vertex_to_index) {
	std::map<PackedVertex, short>::iterator it = vertex_to_index.find(packed);
	if (it == vertex_to_index.end()) {
		return -1;
	} else {
		return it->second;
	}
}

vec3
fill_vec3(float x, float y, float z) {
	vec3 v3 = {x, y, z};
	return v3;
}

vec2
fill_vec2(float x, float y) {
	vec2 v2 = {x, y};
	return v2;
}

int
main() {
	std::vector<vec3> vertices;
	std::vector<vec2> uvs;

	vertices.push_back(fill_vec3(1, 1, 1)); // [0]
	uvs.push_back(fill_vec2(0.1, 0.1));
	vertices.push_back(fill_vec3(2, 2, 2)); // [1]
	uvs.push_back(fill_vec2(0.2, 0.2));
	vertices.push_back(fill_vec3(3, 3, 3)); // [2]
	uvs.push_back(fill_vec2(0.3, 0.3));
	vertices.push_back(fill_vec3(2, 2, 2));
	uvs.push_back(fill_vec2(0.2, 0.2));
	vertices.push_back(fill_vec3(1, 1, 1));
	uvs.push_back(fill_vec2(0.1, 0.1));
	vertices.push_back(fill_vec3(4, 4, 4)); // [3]
	uvs.push_back(fill_vec2(0.4, 0.4));
	vertices.push_back(fill_vec3(4, 4, 4));
	uvs.push_back(fill_vec2(0.4, 0.4));

	std::map<PackedVertex, short> vertex_to_index;
	short index;
	for (unsigned int i = 0; i < vertices.size(); i++) {
		PackedVertex packed = {vertices[i], uvs[i]};
		index = get_index(packed, vertex_to_index);
		if (index < 0) {
			index = vertex_to_index.size();
			vertex_to_index[packed] = index;
		}
	}

	std::map<PackedVertex, short>::iterator iter = vertex_to_index.begin();
	for (; iter != vertex_to_index.end(); iter++) {
		printf("%s %d\n", iter->first.str().c_str(), iter->second);
	}

	return 0;
}

使用 map 容器时,需要元素可以比较,例子中重载 < 操作符真的让我很惊喜。这段代码没有使用指针,因此也不需要显示的释放内存,虽然添加对象到 map 容器中时,会复制 PackedVertex 对象,但是有些场合这种代码还是能满足需求的。

编译。 g++ -o test test.cpp -static 执行结果如下。

(4.000000,4.000000,4.000000)(0.400000,0.400000) 3
(1.000000,1.000000,1.000000)(0.100000,0.100000) 0
(3.000000,3.000000,3.000000)(0.300000,0.300000) 2
(2.000000,2.000000,2.000000)(0.200000,0.200000) 1

© 著作权归作者所有

YLME
粉丝 18
博文 51
码字总数 55990
作品 0
广州
程序员
私信 提问
加载中

评论(0)

Effective STL - 容器

STL(standard template library)提供了一组表示容器,迭代器,函数对象和算法的模板。容器是一个与数组类似的单元,可以存若干个值。 STL容器是同质的,即存储的值的类型相同;算法是完成特...

積木leayn
2013/10/07
159
0
STL"源码"剖析-重点知识总结

1、STL概述 STL提供六大组件,彼此可以组合套用: STL六大组件的交互关系 一些可能令人困惑的C++语法糖: 泛型指针、原生指针和智能指针 2、迭代器   STL的中心思想是:将数据容器和算法分...

ranjiewen
2016/09/20
0
0
[转载][C++]C++ STL容器时间复杂度下的最佳选择

在做题的时候进行时间复杂度分析的时候突然发现不知道vector的操作时间复杂度 转载这篇博文进行分析学习: 原文:C++ STL容器时间复杂度下的最佳选择 ----------------------------------我是...

osc_5ncz8ucr
2018/07/12
2
0
《C++笔记 第二部分 数据结构及STL容器篇》第5章 Set和Map 容器(STL)

5.1 set 集合与映射也是两个常用的容器。set就是数学上的集合——每个元素最多只出现一次。 C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器...

Bruceoxl
03/31
0
0
你懂得C,所以C++也不在话下

前言:C++最初诞生时,仅仅被称作带类的C。这说明C和C++是一衣带水的关系,随后C++扩充了很多特性,成为了面向对象的一个语言,真正成了扛把子。那么C++有什么优势呢?举个例子类比,一个C代...

osc_jdkg3xt0
2018/04/05
9
0

没有更多内容

加载失败,请刷新页面

加载更多

史上最全的“文件或目录损坏且无法读取”的解决办法大集合

问题描述: G盘打不开文件或目录损坏且无法读取,是因为这个I盘的文件系统内部结构损坏导致的。史上最全的“文件或目录损坏且无法读取”的解决办法大集合具体的恢复方法看正文 工具/软件:极...

计算无敌
今天
9
0
2048游戏的最佳算法是什么? - What is the optimal algorithm for the game 2048?

问题: I have recently stumbled upon the game 2048 . 我最近偶然发现了2048游戏。 You merge similar tiles by moving them in any of the four directions to make "bigger" tiles. 您可......

javail
今天
9
0
Spring Cloud Ribbon 客户端负载均衡

Ribbon客户端组件提供一系列完善的配置选项,比如连接超时、重试、重试算法等,内置可插拔、可定制的负载均衡组件。下面是用到的一些负载均衡策略: 简单轮询负载均衡 加权轮询负载均衡 区域...

泥瓦匠BYSocket
今天
7
0
为什么在Python 3中“范围(1000000000000000(1000000000000001))”这么快?

问题: It is my understanding that the range() function, which is actually an object type in Python 3 , generates its contents on the fly, similar to a generator. 据我了解, ra......

技术盛宴
今天
9
0
OSChina 周四乱弹 —— 卖全家桶!

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @巴拉迪维 :陈慧娴的单曲《与泪抱拥》 陈慧娴的嗓音加上向雪怀的词,这样的经典组合真不多。#今日歌曲推荐# 《与泪抱拥》- 陈慧娴 手机党少年...

小小编辑
今天
15
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部