Reputation: 472
How do I resize (adjust both length
and capacity
of) a C++ STL vector without any initialization? Garbage values are acceptable!
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.
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).
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.
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
.
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
Reputation: 75825
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:
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