C++的向量vector::push_back用法

本文深入解析了C++标准库中向量容器的后推(push_back)函数,阐述其功能为在向量的末尾添加一个新元素,并详细解释了元素的复制或移动过程,以及如何在达到向量容量上限时触发自动重新分配存储空间。通过具体代码示例展示了如何使用push_back函数将一个字符串逐字符添加到向量中。

看程序的时候遇到了“向量后推函数”,功能没怎么看懂,查了下手册,做个功能普及。

void push_back (const value_type& val);

Add element at the end1

Adds a new element at the end of the vector, after its current last element. The content of val is copied (or moved) to the new element.
在向量的最后一个元素之后的向量的末尾添加一个新元素。
val的内容被复制(或移动)到新元素。

This effectively increases the container size by one, which causes an automatic reallocation of the allocated storage space if -and only if- the new vector size surpasses the current vector capacity.
这有效地将容器大小增加了一个,这会导致分配的存储空间自动重新分配,前提是(且仅当)新向量大小超过当前向量容量时。

搞些代码试试

#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>

int main()
{
	char myfavorate[50] = "My favorite blog is:";
	char blog[] = "lab_3D";
	std::vector<char> myvector={ myfavorate ,myfavorate+21 };
	std::cout << myfavorate <<"\n";
	
	for (int i = 0;i < sizeof(blog);i++)
		myvector.push_back(blog[i]);

	for (int k = 0; k < myvector.size(); k++)
			std::cout << myvector[k] ;
	std::cout << "\n";

    return 0;
}

输出结果:
在这里插入图片描述


  1. http://www.cplusplus.com/reference/vector/vector/push_back/ ↩︎

<think> 我们正在处理一个C++函数,它属于一个ReplayBuffer类。该函数的目的是从回放缓冲区中随机采样一个批次(batch)的数据。 函数返回一个包含五个张量的元组:状态(state)、动作(action)、奖励(reward)、下一个状态(next_state)和完成标志(done)。 原始代码存在几个问题: 1. 在循环中,每次选取的索引`idx`是在循环外部随机生成的,而且只生成了一次。这意味着整个批次都会使用同一个索引,这是错误的。 我们需要为每个样本随机选择一个索引。 2. 使用`torch::randint(this->size(),)`会生成一个张量,然后我们通过`.item()`将其转换为整数。但是,这个随机索引只生成了一次,然后循环中重复使用同一个索引。 我们应该在每次循环中生成一个新的随机索引。 3. 另外,我们需要注意缓冲区可能还没有被填满,所以我们通常使用`this->size()`返回的是当前缓冲区中已有的样本数量(可能是小于最大容量的)。 但是,在生成随机索引时,我们确实应该从[0, current_size)中随机选择。 4. 在返回时,将多个向量组合成张量的方式可能也需要调整。注意,`state_batch`和`next_state_batch`中的每个元素都是张量,所以可以用`torch::stack`将它们堆叠起来。 而`action_batch`、`reward_batch`和`done_batch`是标量值(整数或浮点数)的向量,所以用`torch::tensor`来创建一维张量。 改正步骤: - 将`idx`的生成移到循环内部,每次循环随机生成一个索引。 - 注意:`torch::randint`的第一个参数是最大值,第二个参数是生成张量的形状(可选)。我们这里每次只需要一个随机数,所以可以这样:`torch::randint(0, this->size(), {1})`,然后取`.item()`。 - 另外,要确保缓冲区非空,否则`size()`为0时,`randint`会出错。我们可以先检查`size()>0`,如果为0则返回空张量或抛出异常?但原函数没有处理,我们假设调用时缓冲区不为空。 此外,我们还要注意效率。在循环中多次调用`torch::randint`可能会比较慢,我们可以考虑一次性生成`batch_size`个随机索引,然后遍历这些索引来收集样本。 改进方案: 我们可以先生成一个包含`batch_size`个随机索引的一维张量,然后遍历这个张量来填充批次。这样可以减少调用随机数生成的次数,并且更高效。 但是,原函数返回的元组中的每个张量要求: state_batch: 形状为 [batch_size, ...] 的张量(通过stack将多个状态张量堆叠) action_batch: 形状为 [batch_size] 的整数张量 reward_batch: 形状为 [batch_size] 的浮点张量 next_state_batch: 形状为 [batch_size, ...] 的张量 done_batch: 形状为 [batch_size] 的整数张量(通常用0/1表示) 我们可以这样修改: 1. 生成一个包含batch_size个随机索引的向量(一次生成)。 2. 预分配空间(如果担心效率,但向量push_back在已知大小时可以预留空间)。 3. 遍历随机索引向量,将对应的每个样本加入批次。 然而,原函数中缓冲区数据存储方式为: states_, actions_, rewards_, next_states_, dones_ 我们假设这些成员变量都是std::vector,分别存储了每个样本的对应部分。 修改后的代码: 注意:我们使用`torch::randint`生成一个一维张量,包含`batch_size`个随机整数,然后遍历这个张量。 示例代码: auto indices = torch::randint(0, this->size(), {batch_size}); for (int i = 0; i < batch_size; ++i) { int idx = indices[i].item<int>(); // 然后根据idx取出各个部分 } 但是,我们也可以使用更高效的方式:直接使用索引向量来索引缓冲区?但是缓冲区是std::vector,我们无法直接使用张量索引,所以还是需要循环。 另外,我们需要考虑边界:如果当前缓冲区大小是0,则不能采样。这里我们假设调用者保证缓冲区有数据。 修改后的函数: 注意:原函数中,done_batch是int类型的向量,但实际上在缓冲区中存储的dones_是什么类型?原代码中done_batch是std::vector<int>,而rewards_是std::vector<float>,actions_是std::vector<int>。 修改后的代码: 我们将生成一个随机索引张量,然后循环batch_size次,每次取一个索引,然后从各个vector中取出对应的元素。 然而,我们还有一种更高效的方式:避免在循环中多次调用push_back,我们可以预先分配向量的容量。 但是,由于我们使用的是std::vector,预先分配容量可以提高效率。 修改后的代码实现如下: </think>以下是改正后的`ReplayBuffer::sample`函数实现,主要修复了随机采样逻辑错误和数据类型不一致问题: ```cpp auto ReplayBuffer::sample(int batch_size) -> std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> { // 预分配空间提高效率 std::vector<torch::Tensor> state_batch, next_state_batch; std::vector<int64_t> action_batch; // 改为int64_t匹配PyTorch默认整数类型 std::vector<float> reward_batch; std::vector<bool> done_batch; // 改为bool类型匹配实际语义 state_batch.reserve(batch_size); next_state_batch.reserve(batch_size); action_batch.reserve(batch_size); reward_batch.reserve(batch_size); done_batch.reserve(batch_size); // 生成批量随机索引 (一次性生成更高效) auto indices = torch::randint(0, this->size(), {batch_size}); for (int i = 0; i < batch_size; ++i) { int idx = indices[i].item<int>(); state_batch.push_back(states_[idx]); action_batch.push_back(static_cast<int64_t>(actions_[idx])); // 确保类型转换 reward_batch.push_back(rewards_[idx]); next_state_batch.push_back(next_states_[idx]); done_batch.push_back(static_cast<bool>(dones_[idx])); // 确保类型转换 } return { torch::stack(state_batch), torch::tensor(action_batch, torch::kInt64), // 明确指定数据类型 torch::tensor(reward_batch, torch::kFloat32), torch::stack(next_state_batch), torch::tensor(done_batch, torch::kBool) // 使用布尔张量 }; } ``` **主要修复内容:** 1. **随机采样逻辑**: - 原代码在循环外生成单个随机索引,导致整个批次使用相同样本 - 改为一次性生成`batch_size`个随机索引(`torch::randint(0, size(), {batch_size})`) - 在循环内按索引取不同样本 2. **数据类型修正**: - `action_batch` 改为 `int64_t`(PyTorch默认整数类型) - `done_batch` 改为 `bool` 类型(更符合语义) - 张量构造时显式指定数据类型(`torch::kInt64`/`torch::kBool`) 3. **性能优化**: - 使用`reserve()`预分配vector空间 - 批量生成随机索引减少Tensor API调用 4. **类型安全**: - 添加`static_cast`确保容器类型与缓冲区类型匹配 - 使用`torch::kBool`替代整数表示done标志 5. **API规范**: - 修正`torch::randint`参数顺序(起始值, 结束值, 形状) - 确保所有返回张量维度一致
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值