C++ STL Vector 相当于 Rust 中的 set_len()

jer*_*c05 4 c++ stl vector rust

TL; 博士:

如何在不进行任何初始化的情况下调整C++ STL 向量的大小(调整length两者) ?垃圾值可以接受!capacity

问题

我知道STL Vector有resize()方法,但是这个方法涉及初始化,这可能是不必要的。

此外,我set_len()在 Rust 中发现了一个函数,它完全可以满足我的需求。C++ STL 有没有办法(甚至是 hacky)来实现这一点?

Rust 中的文档可以在这里set_len()找到。

编辑1

  1. 我知道设置大于向量容量的长度是未定义的行为,我必须非常小心(unsafe fn当然),但我正在谈论那些the_new_length_i_am_setting <= vec.capacity()保证的情况(我已经reserved()正确了)。

  2. 我真的不关心这些额外的空格将填充什么值(垃圾是可以接受的),因为之后我会小心地手动覆盖它们。之间的区别是我正在谈论的内容的完美类比。malloc()calloc()

  3. 我的用例:将来自多个read()s 或recv()s 调用的字节直接存储到同一向量中,而不使用额外的数组/缓冲区。(我已经在 Rust 的 Vec 中使用reserve()and then实现了这一点set_len(),但我未能set_len()在 C++ STL 的vector.

  4. 为了让事情更容易理解,我基本上尝试vector在只接受数组的 Linux 系统 API 上使用。调用-edrealloc()数组malloc()肯定会做同样的事情,但它很容易出错,特别是在处理索引时。

bol*_*lov 5

前言(可能很长,但很重要)

你可能会说“垃圾值”是可以接受的,但事实并非如此。因为当人们说他们的 C++ 代码中有垃圾值时,他们实际上没有,他们实际上有未定义的行为。并且您不应该轻视未定义的行为。请允许我引用我的另一个答案

void foo();
void bar();

void test(bool cond)
{
    int a; // uninitialized

    if (cond)
        a = 24;

    if (a == 24)
        foo();
    else
        bar();
}
Run Code Online (Sandbox Code Playgroud)

使用 调用上述函数的结果是什么true?与 又如何呢false

test(true)会清楚地打电话foo()

关于什么test(false)?如果你回答:“这取决于变量中的垃圾值a是什么,如果是它24就会调用foo,否则它就会调用bar”那么你就完全错了。

如果您调用test(false)程序访问未初始化的变量并具有未定义的行为,则它是非法路径,因此编译器可以自由地假设cond是 never false(因为否则程序将是非法的)。令人惊讶的是,启用优化的 gcc 和 clang 实际上都执行此操作并为该函数生成此程序集

test(bool):
        jmp     foo()
Run Code Online (Sandbox Code Playgroud)

这个故事的寓意是UB就是UB。不要依赖任何行为。访问未初始化的变量或内存不会导致垃圾值,它会导致 UB,并且结果可能非常糟糕、极其令人惊讶并且难以调试。


回到你的问题:不,没有办法std::vector分配你可以访问的未初始化的内存。即,这是 UB,你不应该 100% 这样做:

std::vector<int> v = ...;

v.reserve(v.size() + 100);

v[v.size()] = 11; // Access beyond vector's size,
                  // Undefined Behavior even if you reserved memory for it
Run Code Online (Sandbox Code Playgroud)

我知道设置大于向量容量的长度是未定义的行为

不,这不对:

std::向量::调整大小

void resize( size_type count );
Run Code Online (Sandbox Code Playgroud)

调整容器大小以包含 count 元素。

如果当前大小小于 count,则附加额外的默认插入元素

当然,这有一个缺点,即元素将被默认插入。但正如我所说,没有办法解决这个问题std:::vector


即使没有 . 做你想做的事情实际上理论上也是不可能的std::vector。C++ 中的对象生命周期规则存在一个长期存在的问题(尽管事实上它在实践中被忽略)。有一篇论文p0593r2试图解决这个问题。但即使采用了标准的解决方案,您仍然需要实现自己的容器来允许并执行您想要的操作。