简体   繁体   中英

How to validate pointer to std vector internal array

I would like to write to internal array of vector. I could write using data() if vector is initialised.
However if the vector is empty (but having enough storage), I am not able to write directly to internal array of vector.

#include <vector>
#include <iostream>

using namespace std;

void write_seq(int *v, size_t len)
{
    for (int i = 0; i < len; i++)
        v[i] = i;
}

int main(void)
{
    vector<int> v;
    cout << "reserve and write\n";
    v.reserve(10);
    write_seq(v.data(), v.capacity());
    cout << "seq length " << v.size() << "\n";
    return 0;
}

Output:

$ g++ main.cpp && ./a.out 
reserve and write
seq length 0

How to avoid this kind of situations, is it possible to validate data() pointer of vector?

Edit:
I assumed two things with this question, on an empty vector v; ,

  • v.reserve(10) allocates memory for 10 elements and
  • v.data() points to that allocated memory.

You want to use resize , not reserve , and size instead of capacity . reserve simply gives the vector the added capacity, without actually increasing the size. resize increases the size to match the reserved capacity.

There's no need to concern yourself with how much memory you need to reserve beforehand. If performance is not really an issue, you may consider instead using auto-resizable back inserting iterators to push the elements at the step you want to push them.

#include <vector>
#include <iostream>

template<typename Iterator>
void write_seq(Iterator v) {
    for (int i = 0; i < 10; i++) {
        *v = i;  // actually calls std::vector<>::push_back() internally
        v++;
    }
}

int main(void)
{
    std::vector<int> v;
    std::cout << "just write them data!\n";
    write_seq(std::back_inserter(v));
    std::cout << "seq length " << v.size() << "\n";
    return 0;
}

You need to understand the concept of size and capacity of a vector. size is the number of elements stored while capacity is internal space allocated. capacity is always great than or equal to size. If you insert elements into the vector and caused the vector to run out of capacity, it will automatically increase its capacity by allocating a new space twice of current capacity, then copy existing elements into the new space, then delete the old space.

If you are planning to insert a large number of elements into a vector, the "auto increasing capacity" feature is not efficient, as it will keep allocating new spaces and copying elements. Instead, you can use reserve() to allocate enough space beforehand, and thus to avoid the process to keep allocating new spaces.

capacity(): Returns the number of elements that the container has currently allocated space for.

reserve(): Increase the capacity of the vector to the given size or more.

size(): Returns the number of elements in the container.

resize(): Changes the number of elements stored.


Back to your question, you can simply replace reserve with resize :

int main(void)
{
    vector<int> v;
    cout << "reserve and write\n";
    v.resize(10);  // use resize() instead of reserve()
    write_seq(v.data(), v.size());
    cout << "seq length " << v.size() << "\n";
    return 0;
}


Or, you can insert into the vector directly:

void write_seq(vector<int>& v, size_t len)
{
    for (int i = 0; i < len; i++)
        v.push_back(i);  // add an element to the vector, this changes the size
}

int main(void)
{
    vector<int> v;
    cout << "reserve and write\n";
    v.reserve(10);  // this does not change size, the vector is still empty
    write_seq(v, v.capacity());
    cout << "seq length " << v.size() << "\n";
    return 0;
}

You cannot assign to an element that does not exist. Allocating memory is not sufficient, but your code is fine when you resize the vector (or create it with sufficient elements):

int main(void)
{
    vector<int> v(10);                         // vector with 10 element
    write_seq(v.data(), v.size());             // write to those 10 element
    cout << "seq length " << v.size() << "\n"; // size is (still) 10 
    return 0;
}

Note that your code is not very idomatic. I assume you have reasons for that, but passing iterators to write_seq would be much more natural.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM