使用向量,可以假设元素连续存储在内存中,允许范围 [& vec [0],& vec [vec.capacity())用作正常数组。如,
vector<char> buf;
buf.reserve(N);
int M = read(fd, &buf[0], N);
但现在该向量不知道它包含 M 字节的数据,由 read()外部添加。我知道 vector :: resize()设置了大小,但它也清除了数据,所以它不能用于在 read()之后更新大小调用
是否有一种简单的方法将数据直接读入矢量并更新后的大小?是的,我知道明显的解决方法,例如使用小数组作为临时读缓冲区,并使用 vector :: insert()将其附加到向量的末尾:
char tmp[N];
int M = read(fd, tmp, N);
buf.insert(buf.end(), tmp, tmp + M)
这是有效的(而且这就是我今天所做的),但是如果我可以直接将数据直接放入中,那么我就不会需要额外的复制操作。矢量。
那么,在外部添加数据时,是否有一种简单的方法来修改矢量大小?
答案 0 :(得分:24)
vector<char> buf;
buf.reserve(N);
int M = read(fd, &buf[0], N);
此代码片段调用未定义的行为。即使您保留了空格,也不能写出超过size()
元素的内容。
正确的代码如下:
vector<char> buf;
buf.resize(N);
int M = read(fd, &buf[0], N);
buf.resize(M);
<小时/> PS。您的语句“使用向量,可以假设元素连续存储在内存中,允许范围
[&vec[0], &vec[vec.capacity())
用作普通数组”isn不行。允许的范围是 [&vec[0], &vec[vec.size())
。
答案 1 :(得分:7)
看起来你可以在C ++ 11中做你想做的事情(虽然我自己没有尝试过)。您必须为向量定义自定义分配器,然后使用emplace_back()
。
首先,定义
struct do_not_initialize_tag {};
然后使用此成员函数定义分配器:
class my_allocator {
void construct(char* c, do_not_initialize_tag) const {
// do nothing
}
// details omitted
// ...
}
现在您可以在不初始化数组的情况下向元素添加元素:
std::vector<char, my_allocator> buf;
buf.reserve(N);
for (int i = 0; i != N; ++i)
buf.emplace_back(do_not_initialize_tag());
int M = read(fd, buf.data(), N);
buf.resize(M);
这取决于编译器的优化器。例如,循环可以将size成员变量增加N次。
答案 2 :(得分:2)
在size()
元素之后和之后写入是未定义的行为。
下一个示例以c ++方式将整个文件复制到一个向量中(无需知道文件的大小,也无需在向量中预先分配内存):
#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
typedef std::istream_iterator<char> istream_iterator;
std::ifstream file("example.txt");
std::vector<char> input;
file >> std::noskipws;
std::copy( istream_iterator(file),
istream_iterator(),
std::back_inserter(input));
}
答案 3 :(得分:2)
另一个更新的问题是这个问题的副本,有an answer,看起来就像这里问的那样。这是其副本(第3版)以供快速参考:
已知问题是即使初始化也无法关闭 明确针对
struct NoInitChar { char value; NoInitChar() { // do nothing static_assert(sizeof *this == sizeof value, "invalid size"); static_assert(__alignof *this == __alignof value, "invalid alignment"); } }; int main() { std::vector<NoInitChar> v; v.resize(10); // calls NoInitChar() which does not initialize // Look ma, no reinterpret_cast<>! char* beg = &v.front().value; char* end = beg + v.size(); }
。人们通常会实施自己的{{1}} 任何元素的初始化。
另一种方法是创建一个与char布局兼容的类型, 其构造函数什么都不做:
{{1}}
答案 4 :(得分:1)
您的程序片段已进入未定义行为领域。
当buf.empty()
为真时,buf[0]
具有未定义的行为,因此&buf[0]
也未定义。
这个片段可能会做你想要的。
vector<char> buf;
buf.resize(N); // preallocate space
int M = read(fd, &buf[0], N);
buf.resize(M); // disallow access to the remainder
答案 5 :(得分:0)
您可能希望尝试子类化vector类并实现一个通过直接访问成员变量来设置大小的方法:在GNU C ++中,这可以通过以下代码片段完成:
template <typename T, typename A = mmap_allocator<T> >
class mmappable_vector: public std::vector<T, A> {
public:
void map_into_memory(const size_t n)
{
std::vector<T,A>::reserve(n);
#ifdef __GNUC__
std::vector<T,A>::_M_impl._M_finish = std::vector<T,A>::_M_impl._M_end_of_storage;
#else
#error "Not GNU C++, please either implement me or use GCC"
#endif
}
};
并使用此类(您必须添加一些构造函数)而不是stl :: vector。 但是,除非您处理大于1GB的文件,否则不值得付出努力。
如果你这样做,你可能想尝试一下mmap_allocator(仍然是测试版,可从github.com/johannesthoma/mmap_allocator获得)。