jerryc05
jerryc05

Reputation: 472

C++ STL Vector's equivalent of set_len() in Rust

TL; DR:

How do I resize (adjust both length and capacity of) a C++ STL vector without any initialization? Garbage values are acceptable!

Question

I am aware that STL Vector has resize() method, but this method involves initialization, which might be unnecessary.

Moreover, I found a set_len() function in Rust which does what I want exactly. Is there a way (even hacky) for C++ STL to achieve this?

The set_len() doc in Rust can be found here.

EDIT 1

  1. I am aware that setting a length that is larger than the vector's capacity is undefined behavior, and I have to be very careful (unsafe fn, sure enough), but I am talking about those cases where the_new_length_i_am_setting <= vec.capacity() is GUARANTEED (I have already reserved() correctly).

  2. I don't really care what values will be filled into those extra spaces (garbage is acceptable) since I will manually overwrite them carefully afterward. The difference between malloc() and calloc() is a perfect analogy of what I am talking about.

  3. My use case: store bytes from multiple read()s or recv()s calls into the same vector directly without using an extra array/buffer. (I have achieved this in Rust's Vec using reserve() and then set_len(), but I failed to find an equivalent function for set_len() in C++ STL's vector.

  4. To make things easier to understand, I am basically trying to use vector on Linux system APIs which only arrays are accepted. Calling realloc() on a malloc()-ed array will definitely do the same, but it is error-prone, especially when dealing with indices.

Upvotes: 4

Views: 532

Answers (1)

bolov
bolov

Reputation: 75825

Preface (this might be long, but it's very important)

You might say that "garbage values" are acceptable, but they are not. Because when people say they have garbage values in their C++ code they really don't, they actually have Undefined Behavior. And you shouldn't take lightly Undefined Behavior. Allow me to quote from another answer of mine:

void foo();
void bar();

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

    if (cond)
        a = 24;

    if (a == 24)
        foo();
    else
        bar();
}

What is the result of calling the above function with true? What about with false?

test(true) will cleary call foo().

What about test(false)? If you answer: "Well it depends on what garbage value is in variable a, if it is 24 it will call foo, else it will call bar" Then you are completely wrong.

If you call test(false) the program accesses an uninitialized variable and has Undefined Behavior, it is an illegal path and so the compilers are free to assume cond is never false (because otherwise the program would be illegal). And surprise surprise both gcc and clang with optimizations enabled actually do this and generate this assembly for the function:

test(bool):
        jmp     foo()

The moral of the story is that UB is UB. Don't rely on any kind of behavior. Accessing uninitialized variables or memory doesn't result in garbage values, it results in UB and the results can be very bad, extremely surprising and difficult to debug.


Going back to your question: no there is no way in std::vector to allocate uninitialized memory you can access. I.e. this is UB and you should 100% not do this:

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

I am aware that setting a length that is larger than the vector's capacity is undefined behavior

No, it's not:

std::vector::resize

void resize( size_type count );

Resizes the container to contain count elements.

If the current size is less than count, additional default-inserted elements are appended

Of course, this has the disadvantage that elements will be default-inserted. But as I've said there is no way around this in std:::vector


To do what you want is actually theoretically impossible even without std::vector. There is a long lasting issue with the object lifetime rules in C++ (even though de-facto it is ignored in practice). There is a paper p0593r2 which tries to solve this. But even with a solution adopted into the standard you would still need to implement your own container to allow and do what you desire.

Upvotes: 5

Related Questions