使用指针写入 std 容器
Using pointers to write to a std container
我希望能够创建一个固定长度的容器(vector
? deque
?以充当缓冲区,然后为另一个对象向量提供一个指针,指向允许它们写入的缓冲区位置。
示例(不可编译的代码(
class Item {
*p //pointer to a place in the vector
vector<int> values
}
vector<Item> items;
for(auto item : items) {
for(auto value : values) {
buffer[p] = item->value
++(item->p);
}
}
但是,我不确定如何使每个Item
都清楚他们应该在缓冲区中开始写入的关系。
我应该注意的是,对于items
的每次迭代,最终缓冲区都有一个已知的固定大小 - 但是在函数调用之间,Items
的数量可能会改变。
谢谢
如果我正确理解了这个问题(我不确定(,你应该使用索引,而不是指针或迭代器,因为它是缓冲区开头的相对偏移量,而不是缓冲区更改会使失效的绝对地址。
class Item
{
size_t pos; // index into the buffer
vector<int> values;
};
vector<Item> items;
// ...
std::vector<int> buffer;
buffer.resize(N);
for (auto& item : items)
{
assert(buffer.size() >= (item.pos + item.values.size()));
std::copy(std::begin(item.values), std::end(item.values),
std::begin(buffer)+item.pos);
}
这将与vector
或deque
一起使用作为缓冲区(或RandomAccessIterators的任何其他内容(,但是由于您似乎不需要在缓冲区的开头添加/删除元素(仅调整一次大小并分配给现有元素(,因此没有理由使用deque. Therefore you should prefer
vector',这通常应该是您默认选择的容器,除非您需要其中一个的特定特征器皿。
我不知道您打算如何设置Item::pos
值,也许这是有道理的:
size_t pos = 0;
for (auto& item : items)
{
item.pos = pos;
pos += item.values.size();
assert(buffer.size() >= pos);
std::copy(std::begin(item.values), std::end(item.values),
std::begin(buffer)+item.pos);
}
这会将每个项目依次放入缓冲区中,并动态记录位置。
这甚至可以在事先不知道总缓冲区大小的情况下工作,根据需要调整缓冲区大小:
size_t pos = 0;
for (auto& item : items)
{
item.pos = pos;
pos += item.values.size();
if (buffer.size() < pos)
buf.resize(pos);
std::copy(std::begin(item.values), std::end(item.values),
std::begin(buffer)+item.pos);
}
由于您存储的是索引,而不是绝对地址,因此即使在调整缓冲区大小并将其内容重新定位到其他内存块后,它也会继续工作。
我应该注意,对于
items
的每次迭代,最终缓冲区都有一个已知的固定大小 - 但是在函数调用之间,Items
的数量可能会改变。
正如我的评论中所述,您将获取并跟踪std::vector<whatever>
中包含的值的指针和引用是不稳定的,只要允许通过push_back()
、erase()
或任何其他此类操作更改向量。
不过,您可以选择
-
参考向量的索引。即使
std::vector<>
需要重新分配和复制,这些也将是稳定的。 -
使用智能指针,例如
std::unique_ptr<>
或std::shared_ptr<>
存储在std::vector<>
中,而不是存储在实例副本中。
这完全取决于您的实际用例,这将是正确的方法。
正如其他人已经评论的那样,我不确定您要实现什么,但是您的原始代码与可以编译并且具有明确定义(尽管相当无用(的行为相距不远。
我想你可能打算写以下内容:
#include <vector>
#include <iostream>
struct Item
{
std::vector<int>::iterator p;
std::vector<int> values;
Item() : values {'H', 'A', 'P', 'P', 'Y'}
{
this->p = values.begin();
}
};
std::ostream&
operator<<(std::ostream& os, const Item& item)
{
os << "[";
for (std::size_t i = 0; i < item.values.size(); ++i)
os << (i ? ", " : "") << item.values.at(i);
os << "]";
return os;
}
int main()
{
std::vector<Item> items {4};
for (auto& item : items)
{
for (auto value : item.values)
{
*(item.p) = value; // Note: self-assignment with no effect
++(item.p);
}
}
for (auto& item : items)
std::cout << item << std::endl;
}
这个特定的程序表现良好,但使用这种数据结构,您迟早会搬起石头砸自己的脚。 可能有更好的解决方案。
- 除了 std::vector 之外,是否有一个 std 容器不会复制和销毁作为类的元素?
- 是否可以确定传递的迭代器是否属于关联的 std 容器?
- 管理 std 容器中的抽象类
- 通过模板访问 std 容器的迭代器
- 使用ENABLE_IF和SFINAE时,功能参数类型扣除(std容器,例如向量)失败
- 是否可以使 std 容器使用默认运算符为新?
- 不同编译器中的STD容器的不同NOExcept属性
- 有没有一种透明的方式来在 std 容器中使用unique_ptr
- 如何从 std 容器的迭代器为成员元素创建迭代器
- 在自身中创建模板类的 STD 容器
- std容器元素的构造正确性
- 在 std::move 之后重复使用 std 容器是否安全
- 从另一个线程调用 std 容器上的大小是否安全
- 在 std:: 容器中使用受保护继承的原因
- boost::格式化和自定义打印 STD 容器
- 使用 boost 对多个 std 容器进行基于范围的迭代的概念问题
- 在发生异常时从 std 容器释放内存的策略bad_alloc
- Visual Studio Debugger:查看 std::list(和其他 std 容器)
- 将原始数据封装在类似std容器的数组中,具有运行时大小
- 将std容器传递给函数