STD::Vector- write directly to the internal array - c++

Is the following code ok?:
std::vector<char> var;
size_t requiredSize;
getenv_s(&requiredSize, NULL, 0, "Something");
if (requiredSize == 0)
{
return ENV_NOT_EXIST;
}
if(var.size() < requiredSize)
var.resize(requiredSize);
// Get the value of the environment variable.
getenv_s(&requiredSize, &var[0], requiredSize, "Something");
std::string str(var.begin(),var.end());
If this code is OK, can someone please explain me how the begin() and the end() values of the var vector are updated? it looks like this code changes directly the internal array of the vector, not over the std::vector api - so how these values are updated to the actual size?

std::vector guarantees data to be stored contiguously, so writing to data, as long as you do not overrun the end is perfectly fine:
From the C++11 standard section 23.3.6.1.1:
The elements of a vector are stored contiguously, meaning that if v is
a vector where T is some type other than bool, then it
obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
However, note that resizing the vector might move the data and invalidate iterators.
Unfortunately, the standard does not require std::vector<T>::iterator to be a raw pointer type (although it usually is). So, you cannot portably use std::vector<T>::begin() to access the first element. There is std::vector<T>::data(), which returns a pointer to the first element and which can be used for code that expects raw c-arrays.
I suggest to rewrite your call like this:
getenv_s(&requiredSize, var.data(), var.size(), "Something");
if (requiredSize < var.size())
var.resize(requiredSize);

Related

convert std vector to char and viceversa [duplicate]

This question already has an answer here:
Convert std::vector to array
(1 answer)
Closed 7 years ago.
I have a library function from which I should pass same data types to the main application .
Thus my question is - how do I pass a std::vector<char> to a C style function that expects char*. Here is what I have tried
// function to apply on char
void somefunction (char* c_buf, int* c_buf_len)
// main function
typedef std::vector<char> Buf;
void (Buf& buf)
{
// first convert `buf` to char and call function
somefunction(char_buf, char_buf_len)
// Now convert buf to vector and do something with it..
}
You cannot convert a vector to char. They're completely unrelated types. Good news is that you seem to need a pointer to a character buffer and a vector<char> is exactly that. You get the pointer to the begginning of its storage by taking the address of the first element (&buf[0]) or by saying buf.data(). buf.size() will give you (you guessed it!) the size of the buffer. That's all you need to call somefunction.
To pass a std::vector<char> to a function that expects a char *, you can
1) Pass the address of the first element in the vector. The only caveat is that using this method requires that the vector is not empty.
if (!buf.empty())
somefunction(&buf[0], buf.size());
2) If using C++ 11 use the data() method for the vector. In C++ 11, using data guarantees that it will work with an empty vector.
somefunction(buf.data(), buf.size());
Like this:
void (Buf& buf)
{
int len = buf.size();
somefunction(&buf[0], &len);
// ...
}
int len = buf.size();
somefunction(&buf[0], &len);
You can do that because (From n2798 (draft of C++0x)):
23.2.6 Class template vector [vector]
1 A vector is a sequence container that supports random access iterators. In addition, it supports (amortized)
constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage
management is handled automatically, though hints can be given to improve efficiency. The elements of a
vector are stored contiguously, meaning that if v is a vector where T is some type other
than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().

c++ std::copy input iterator (pointers) to vector

Hi I'm trying to understand why the following code does not work. I'm trying to use pointers as the input iterator type to the std::copy algorithm. fsRead.Buffer points to the beginning of the data I want to copy, and fsRead.BufferSize is size of the data that we want to copy.
// AllocateZeroPool(UINT64) takes an input size, and returns a pointer to allocated memory. (this is the existing C api)
fsRead.Buffer = static_cast<UINT8*>(AllocateZeroPool(fsRead.BufferSize));
//
// this next line populates the data into fsRead.Buffer
auto status = mFs->read_data(nullptr, &fsRead);
the type of file.data is: std::vector<UINT8>
std::copy(fsRead.Buffer, fsRead.Buffer + fsRead.BufferSize, file.data.begin());
file.data.size() is zero with the above std::copy() call.
To get the data into the vector file.data, I currently do the copy by hand:
for(auto i(0U); i < fsRead.BufferSize; ++i) {
file.mBinaryData.emplace_back(fsRead.Buffer[i]);
}
Why does using two pointers as input iterators not seem to work?
edit: To clarify I mean that no data is actually copied into the file.mBinaryData vector.
With std::vector you must use a std::back_inserter. Without it the iterator will not do a push_back to copy the data, but just increment the given iterator.
std::copy(fsRead.Buffer, fsRead.Buffer + fsRead.BufferSize, std::back_inserter(file.data));
This fails because accessing iterators to a vector never change the size of the vector.
You can use one of the standard iterator adapters, such as back_inserter, to do this instead. That would look like this:
// Looks like you really wanted copy_n instead...
std::copy_n(fsRead.Buffer, fsRead.BufferSize, std::back_inserter(file.data));

Copying an array into a std::vector

I was searching about this topic and I found many ways to convert an array[] to an std::vector, like using:
assign(a, a + n)
or, direct in the constructor:
std::vector<unsigned char> v ( a, a + n );
Those solve my problem, but I am wondering if it is possible (and correct) to do:
myvet.resize( 10 );
memcpy( &myvet[0], buffer, 10 );
I am wondering this because I have the following code:
IDiskAccess::ERetRead nsDisks::DiskAccess::Read( std::vector< uint8_t >& bufferRead, int32_t totalToRead )
{
uint8_t* data = new uint8_t[totalToRead];
DWORD totalRead;
ReadFile( mhFile, data, totalToRead, &totalRead, NULL );
bufferRead.resize( totalRead );
bufferRead.assign( data, data + totalRead );
delete[] data;
return IDiskAccess::READ_OK;
}
And I would like to do:
IDiskAccess::ERetRead nsDisks::DiskAccess::Read( std::vector< uint8_t >& bufferRead, int32_t totalToRead )
{
bufferRead.resize( totalToRead );
DWORD totalRead;
ReadFile( mhFile, &bufferRead[0], totalToRead, &totalRead, NULL );
bufferRead.resize( totalRead );
return IDiskAccess::READ_OK;
}
(I have removed the error treatment of the ReadFile function to simplify the post).
It is working, but I am affraid that it is not safe. I believe it is ok, as the memory used by the vector is continuous, but I've never seen someone using vectors this way.
Is it correct to use vectors like this? Is there any other better option?
Yes it is safe with std::vector C++ standard guarantees that the elements will be stored at contiguous memory locations.
C++11 Standard:
23.3.6.1 Class templatevector overview [vector.overview]
A vector is a sequence container that supports random access iterators. In addition,itsupports(amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency. The elements of a vector are stored contiguously, meaning that ifv is avector whereT is some type other than bool, then it obeys the identity&v[n] == &v[0] + n for all0 <= n < v.size().
Yes, it is fine to do that. You might want to do myvet.data() instead of &myvet[0] if it looks better to you, but they both have the same effect. Also, if circumstances permit, you can use std::copy instead and have more type-safety and all those other C++ standard library goodies.
The storage that a vector uses is guaranteed to be contiguous, which makes it suitable for use as a buffer or with other functions.
Make sure that you don't modify the vector (such as calling push_back on it, etc) while you are using the pointer you get from data or &v[0] because the vector could resize its buffer on one of those operations and invalidate the pointer.
That approach is correct, it only depends on the vector having contiguous memory which is required by the standard. I believe that in c++11 there is a new data() member function in vectors that returns a pointer to the buffer. Also note that in the case of `memcpy you need to pass the size in bytes not e size of the array
The memory in vector is guaranteed to be allocated contiguously, and unsigned char is POD, therefore it is totally safe to memcpy into it (assuming you don't copy more than you have allocated, of course).
Do your resize first, and it should work fine.
vector<int> v;
v.resize(100);
memcpy(&v[0], someArrayOfSize100, 100 * sizeof(int));
Yes, the solution using memcpy is correct; the buffer held by a vector is contiguous. But it's not quite type-safe, so prefer assign or std::copy.

std::vector and contiguous memory of multidimensional arrays

I know that the standard does not force std::vector to allocate contiguous memory blocks, but all implementations obey this nevertheless.
Suppose I wish to create a vector of a multidimensional, static array. Consider 2 dimensions for simplicity, and a vector of length N. That is I wish to create a vector with N elements of, say, int[5].
Can I be certain that all N*5 integers are now contiguous in memory? So that I in principle could access all of the integers simply by knowing the address of the first element? Is this implementation dependent?
For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*.
The standard does require the memory of an std::vector to be
contiguous. On the other hand, if you write something like:
std::vector<std::vector<double> > v;
the global memory (all of the v[i][j]) will not be contiguous. The
usual way of creating 2D arrays is to use a single
std::vector<double> v;
and calculate the indexes, exactly as you suggest doing with float.
(You can also create a second std::vector<float*> with the addresses
if you want. I've always just recalculated the indexes, however.)
Elements of a Vector are gauranteed to be contiguous as per C++ standard.
Quotes from the standard are as follows:
From n2798 (draft of C++0x):
23.2.6 Class template vector [vector]
1 A vector is a sequence container that supports random access iterators. In addition, it supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency. The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
C++03 standard (23.2.4.1):
The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
Also, see here what Herb Sutter's views on the same.
As #Als already pointed out, yes, std::vector (now) guarantees contiguous allocation. I would not, however, simulate a 2D matrix with an array of pointers. Instead, I'd recommend one of two approaches. The simpler by (by far) is to just use operator() for subscripting, and do a multiplication to convert the 2D input to a linear address in your vector:
template <class T>
class matrix2D {
std::vector<T> data;
int columns;
public:
T &operator()(int x, int y) {
return data[y * columns + x];
}
matrix2D(int x, int y) : data(x*y), columns(x) {}
};
If, for whatever reason, you want to use matrix[a][b] style addressing, you can use a proxy class to handle the conversion. Though it was for a 3D matrix instead of 2D, I posted a demonstration of this technique in previous answer.
For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*.
That's not a 2D array, that's an array of pointers. If you want a real 2D array, this is how it's done:
float (*p)[5] = new float[N][5];
p [0] [0] = 42; // access first element
p[N-1][4] = 42; // access last element
delete[] p;
Note there is only a single allocation. May I suggest reading more about using arrays in C++?
Under the hood, a vector may look approximately like (p-code):
class vector<T> {
T *data;
size_t s;
};
Now if you make a vector<vector<T> >, there will be a layout like this
vector<vector<T>> --> data {
vector<T>,
vector<T>,
vector<T>
};
or in "inlined" form
vector<vector<T>> --> data {
{data0, s0},
{data1, s1},
{data2, s2}
};
Yes, the vector-vector therefore uses contiguous memory, but no, not as you'd like it. It most probably stores an array of pointers (and some other variables) to external places.
The standard only requires that the data of a vector is contiguous, but not the vector as a whole.
A simple class to create, as you call it, a 2D array, would be something like:
template <class T> 2DArray {
private:
T *m_data;
int m_stride;
public:
2DArray(int dimY, int dimX) : m_stride(dimX) : m_data(new[] T[dimX * dimY]) {}
~2DArray() { delete[] m_data; }
T* operator[](int row) { return m_data + m_stride * row; }
}
It's possible to use this like:
2DArray<int> myArray(30,20);
for (int i = 0; i < 30; i++)
for (int j = 0; j < 20; j++)
myArray[i][j] = i + j;
Or even pass &myArray[0][0] as address to low-level functions that take some sort of "flat buffers".
But as you see, it turns naive expectations around in that it's myarray[y][x].
Generically, if you interface with code that requires some sort of classical C-style flat array, then why not just use that ?
Edit: As said, the above is simple. No bounds check attempts whatsoever. Just like, "an array".

sizeof() a vector

I have a vector<set<char> > data structure (transactions database) and I want to know the size of it. When I use sizeof() with each set<char> the size is 24 in spite of the set contains 3, 4 or 5 chars. Later, when I use sizeof() with the vector<set<char> > the size is 12... I suppose this is not the way to know the size of a data structure. Any help?
Thanks.
You want vector::size() and set::size().
Assuming v is your vector, do this:
size_t size = 0;
for (vector<set<char> >::const_iterator cit = v.begin(); cit != v.end(); ++cit) {
size += cit->size();
}
sizeof() is giving you the in-memory size of the object/type it is applied to, in multiples of sizeof(char) (usually one byte). If you want to know the in-memory size of the container and its elements, you could do this:
sizeof(v) + sizeof(T) * v.capacity(); // where T is the element type
sizeof returns size of object itself. if it contains pointer to array for example it will not count size of array, it will count only size of pointer (4 on 32 bits) for vector use .size
Vector is implemented using internal pointers to the actual storage. Hence sizeof() will always return the same result which does not include the data storage itself. Try using the vector::size() method instead. This will return the number of elements in the vector.
sizeof() is computed at compile time, so there is no way it can tell you how many elements it has inside.
Use the size() method of the vector object.
vector in STL is a class template, when you give template parameter inside <SomeType> following vector, C++ compiler generated code for a class of type SomeType. So when you populate the vector using push_back, you are actually inserting another object of SomeType so when you request .size() from the compiler it gives you the number of SomeType objects inserted by you.
Hope that helps!
Use vector::size() member function to find out number of items in the vector. Hint - they are allocated on the free store.