I want to write a function to create an array with a viewed vector.
Such as
int foo(vector<int> &A){
int N=A.size();
int myarray[N]={0}; //here is an error
}
Here are my questions:
I know to build an array must use const value but vector::size() isn't return a const value?
using const modify the expression doesn't work N still a variable.
I don't see why you ever should need to create an array. If you pass arrays anywhere into a function, you pass a pointer to such an array. But you easily can get the vector's internal data as such a pointer:
std::vector<int> v({1, 2, 3, 4});
int* values = v.data();
Done, you have your "array", and you don't even have to copy the data...
If you still need a copy, just copy the vector itself.
Side-note: The vector's content is guaranteed by the standard to be contiguous, so you won't get into any trouble iterating over your "arrays".
However, one problem actually exists: If you want to store pointers to the contents of your array, they might get invalidated if you add further elements into your vector, as it might re-allocate its contents. Be aware of that! (Actually, the same just as if you need to create a new array for any reason...)
Related
I have a templated class I use to create and manipulate a jagged array. I can create the jagged array; add elements; remove them; modify them; print the jagged array, etc. It seems to work at least as far my testing so far, until I try to pass a previously created jagged array to it to create another. My class currently takes what is passed, and creates what appears to be a clone, but it ends up being an alias for the same memory space. So, when I go to make a change in what I think is the clone, I end up making the change in 'both' of them. I'm kind of lost and was wondering if anyone might be able to give me some pointers?
It's hard to tell exactly what your problem is without a code example, but it sounds like your array contains pointers. For example:
std::vector<int*> original;
original.push_back(new int[]{1}); // note: for demo only (`new` without `delete` is bad)
std::vector<int*> copy = original;
copy[0][0] = 2; // now original[0][0] also equals 2
Since copy contains the same pointers as original, original[0] and copy[0] are the same pointer, and so original[0][0] and copy[0][0] refer to the same object.
You can fix this by copying the values being pointed to, rather than the pointers themselves, and storing pointers to the copies in your new array. In my example, the easiest way would be to use std::vector<int> instead of int*:
std::vector<std::vector<int>> original;
original.push_back({1});
std::vector<std::vector<int>> copy = original;
copy[0][0] = 2; // original[0][0] still equals 1
I want to know if there is a way to keep track of addresses of elements in a vector.
I like to use vector of solid elements like std::vector<MyObject> vec because:
std::vector do all the allocation / deallocation stuff for me
it also ensures me that my elements are stored in contiguous memory
I can get benefits of all code that work with vectors (e.g. <algorithm>)
This is exactly what I want. The problem arises when I want to store the address / reference of elements of my vector in other objects. In fact, the problem really arises when std::vector need to reallocate memory.
I tried to find alternatives to my problem:
Use vector of pointers / smart pointers : No, the pointers will be allocated contiguously but not the elements
Use vector of pointers / smart pointers and write my own operator new/new[] for MyObject : Humm, that seems better but no. By using a vector to allocate my elements I can say : "those particular set (I do not refer here to std::set) of elements must be allocated contiguously, not all". In fact I may want to have other set of elements that should be allocated contiguously because of the way I want to use them and using a vector to do that is exactly what (I think) I need. Thats also implies that I'm doing the job I want the vector to do.
Why not using boost multi-index? : In some ways that will do what I want because I want to store pointers/smartpointers of my vector elements in other containers. But no again because I really want to store reference/pointer/smartpointer of my vector's elements inside other objects, not just other containers.
What I would loved to have is a vector that can give me a pointer object that will allways point the the address of the desired element and I will use it like that :
std::vector<MyObject> vec;
// insert some elements
...
// get a pointer object by index or by using an iterator
// does something like that exist?
std::vector<MyObject>::pointer ptr = vec.get_pointer_at(5);
// do what I want on the vector except removing the element
...
// use my pointer whatever reallocations occurred or not
ptr->doSomething();
That sounds like an iterator that will never be invalidated except the fact I don't need/want to perform arithmetic on it (+x, -x, ++, --).
So, can someone leads me to the way to achieve what I want or explain me why/where I'm wrong wanting to do this? Please accept my apologize for my lack of knowledge in STL if there is a well known solution that I missed / or if this question has already be answered.
Edit:
I think that if I have to code such kind of pointer, that means that I'm wanting something useless or I'm wrong somewhere (unless someone should have already wrote a template for that) . So I'm more looking to a validated C++ idiom to get rid of this problem.
Although std::vector does not give you such pointer, there is no reason why you cannot make one yourself. All it takes is a class that keeps a reference to the std::vector object and the index, and overloads the prefix operator * and the infix operator -> (you need four overloads - const and non-const for each operator).
You would use this pointer like this:
std::vector<int> vect = {2, 4, 6, 8, 10, 12, 14, 16};
vect_ptr<int> ptr(vect, 5); // <<== You need to implement this
*ptr = 123;
cout << *ptr << endl;
The implementation of these overloads would grab the std::vector's begin() iterator, and return the result of calling vect.at(index). This would look like a pointer from the outside, but the object to which it points would change as the content of the std::vector gets resized.
As far as I know, there is nothing in the standard library nor in Boost to address your problem. A solution would be to implement your own kind of element pointer:
template<typename T>
class vector_element
{
public:
vector_element( std::vector<T>& v, std::size_t i )
: m_container( v ), m_element_index(i)
{ }
T& operator*() { return m_container[m_element_index]; }
T* operator->() { return &m_container[m_element_index]; }
private:
std::vector<T>& m_container;
std::size_t m_element_index;
};
In C++ I understand that in order to create a dynamic array you need to use vectors. However I have a problem when I need to find information I put in the vector.
For example:
Lets say I have a simple vector that stores the name of a person and a small message the wrote. In the vector how do I find where Bill is located.
I was also trying to understand how to do this in PHP when I posted this question.
Indeed you seam confused. Let me try to help you.
One thing that is maybe confusing you: std::vector is not a geometric vector. It's only a sequence of data of the same type that is contiguous in memory. So it's like an array.
a) Determine the size of a vector based on a variable. For example if
I was using an array it would look something like array [x][y] ( I
know it's not possible to do this). How would I do this with a vector
std::vector is basically a automatically managed dynamic array.
It means that it IS an array inside, but it's managed by code that will make sure that array grows (gets bigger) when you try to add more data than it current capacity can hold.
Actually, std::vector is a class template. It means that it's not a real class, it's code that the compiler will use to generate itself a real class. If I say
std::vector<int> my_ints; // this is a vector of ints
This vector can only hold ints. And then:
std::vector<std::string> name_list;
this one hold std::string objects.
As I was saying, inside, it's only code to manage an array dynamically. You can think the previous examples as if it was like that:
class
{
unsigned long size; // count of elements contained in this container
unsigned long capacity; // count of elements that the memory allocated by the array can hold
int* array; // array containing the values, created using new, destroyed using delete
}
my_ints;
This is an oversimplified view of how it is inside, so don't assume it's exactly like that, but it might be useful.
Now, when you add values, the value is copied in the memory of the array, in an element that is not used yet (through push_back() for example) or writing over an element already existing (using insert() for example).
If you add a value and the capacity of the vector is not enough to hold all values, then the the vector will automatically grow: it will create a much bigger array, copy it's current values inside, copy the additional value too, then delete the array it had before.
It's important to understand this: if a vector grows, then you can't assume that it's data is always at the same adress in memory, so pointers to it's data can't be trusted.
b) second how would I using the push back command to store the value
of a variable inside a specific spot. Again if I was using an array
it'd be like array[x][y] += q. Where x and y are the spot in the array
and q is the value.
You don't use push_back() to add a value between two values, you use insert().
The syntaxe array[x][y] += q Will certainly not do what you describe. It will add q to the value at the position array[x][y].
Arrays are different to std::vector because they are of a fixed size. All elements of the array exist while the array exists. When you create a std::vector with its default constructor, it is empty. It contains no elements, so you cannot index any elements.
However, std::vector does have a constructor that takes the initial size. If you pass a single int argument to the std::vector constructor, it will default initialise that many elements. For example:
std::vector<int> v(10); // Will have 10 ints
If you want the equivalent of a 2D array, then you'll need a std::vector<std::vector<T>>. If you want to construct it with a specific size, you will need specify the size of the outer std::vector as above, and pass it the std::vector that each element should be initialised to. For example, if you want a 10x20 vector:
// This will have 10x20 ints
std::vector<std::vector<int>> v(10, std::vector<int>(20));
Once these elements exist, you can index them just as you would an array:
int value = v[x][y];
It's worth noting that C++11 introduces std::array which has a compile-time fixed size. You could use it like this:
std::array<std::array<int, 20>, 10> arr;
However, you cannot use this if you want your array size to be determined by a variable. The dimensions must be compile-time constants.
If I have a vector in C++, I know I can safely pass it as an array (pointer to the contained type):
void some_function(size_t size, int array[])
{
// impl here...
}
// ...
std::vector<int> test;
some_function(test.size(), &test[0]);
Is it safe to do this with a nested vector?
void some_function(size_t x, size_t y, size_t z, int* multi_dimensional_array)
{
// impl here...
}
// ...
std::vector<std::vector<std::vector<int> > > test;
// initialize with non-jagged dimensions, ensure they're not empty, then...
some_function(test.size(), test[0].size(), test[0][0].size(), &test[0][0][0]);
Edit:
If it is not safe, what are some alternatives, both if I can change the signature of some_function, and if I can't?
Short answer is "no".
Elements here std::vector<std::vector<std::vector<int> > > test; are not replaced in contiguous memory area.
You can only expect multi_dimensional_array to point to a contiguos memory block of size test[0][0].size() * sizeof(int). But that is probably not what you want.
It is erroneous to take the address of any location in a vector and pass it. It might seem to work, but don't count on it.
The reason why is closely tied to why a vector is a vector, and not an array. We want a vector to grow dynamically, unlike an array. We want insertions into a vector be a constant cost and not depend on the size of the vector, like an array until you hit the allocated size of the array.
So how does the magic work? When there is no more internal space to add a next element to the vector, a new space is allocated twice the size of the old. The old space is copied to the new and the old space is no longer needed, or valid, which makes dangling any pointer to the old space. Twice the space is allocated so the average cost of insertion to the vector that is constant.
Is it safe to do this with a nested vector?
Yes, IF you want to access the inner-most vector only, and as long you know the number of elements it contains, and you don't try accessing more than that.
But seeing your function signature, it seems that you want to acess all three dimensions, in that case, no, that isn't valid.
The alternative is that you can call the function some_function(size_t size, int array[]) for each inner-most vector (if that solves your problem); and for that you can do this trick (or something similar):
void some_function(std::vector<int> & v1int)
{
//the final call to some_function(size_t size, int array[])
//which actually process the inner-most vectors
some_function(v1int.size(), &v1int[0]);
}
void some_function(std::vector<std::vector<int> > & v2int)
{
//call some_function(std::vector<int> & v1int) for each element!
std::for_each(v2int.begin(), v2int.end(), some_function);
}
//call some_function(std::vector<std::vector<int> > & v2int) for each element!
std::for_each(test.begin(), test.end(), some_function);
A very simple solution would be to simply copy the contents of the nested vector into one vector and pass it to that function. But this depends on how much overhead you are willing to take.
That being sad: Nested vectorS aren't good practice. A matrix class storing everything in contiguous memory and managing access is really more efficient and less ugly and would possibly allow something like T* matrix::get_raw() but the ordering of the contents would still be an implementation detail.
Simple answer - no, it is not. Did you try compiling this? And why not just pass the whole 3D vector as a reference? If you are trying to access old C code in this manner, then you cannot.
It would be much safer to pass the vector, or a reference to it:
void some_function(std::vector<std::vector<std::vector<int>>> & vector);
You can then get the size and items within the function, leaving less risk for mistakes. You can copy the vector or pass a pointer/reference, depending on expected size and use.
If you need to pass across modules, then it becomes slightly more complicated.
Trying to use &top_level_vector[0] and pass that to a C-style function that expects an int* isn't safe.
To support correct C-style access to a multi-dimensional array, all the bytes of all the hierarchy of arrays would have to be contiguous. In a c++ std::vector, this is true for the items contained by a vector, but not for the vector itself. If you try to take the address of the top-level vector, ala &top_level_vector[0], you're going to get an array of vectors, not an array of int.
The vector structure isn't simply an array of the contained type. It is implemented as a structure containing a pointer, as well as size and capacity book-keeping data. Therefore the question's std::vector<std::vector<std::vector<int> > > is more or less a hierarchical tree of structures, stitched together with pointers. Only the final leaf nodes in that tree are blocks of contiguous int values. And each of those blocks of memory are not necessarily contiguous to any other block.
In order to interface with C, you can only pass the contents of a single vector. So you'll have to create a single std::vector<int> of size x * y * z. Or you could decide to re-structure your C code to handle a single 1-dimensional stripe of data at a time. Then you could keep the hierarchy, and only pass in the contents of leaf vectors.
To create an array of strings this works:
std::string array[] = {
"first",
"second",
:
"last"
};
If I try to do the same with vectors it doesn't work:
std::vector<int> array[] = {
{1, 2},
{3, 4, 5}
:
{9}
};
I get "non-aggregates cannot be initialized with initializer list".
What is the correct syntax to initialise the array of vectors?
Note that I need to do it in one go like this and not using vector member functions to fill the vectors with ints one at a time (because I'm trying to set up a file that will create the array at compile time based upon the initialisation numbers, so calling member functions doesn't help in this case).
Although the purpose of using an array of vectors is very much questionable (why not use vector of vectors or a two-dimentional array then?), to do what you want the correct syntax would look like:
std::vector<int> array[] = {
vector<int>(2),
vector<int>(3),
//...
vector<int>(1)
};
The reason it doesn't make any sense, is because in this case it's semantically the same as creating an array of pointers:
int* array[] = {
new int[0],
new int[0],
//...
new int[0],
};
with the only difference is that internally std::vector is managing the lifetime of these pointers all by itself. That means that unless you're creating a constant-size vector (i.e. without a possibility for the vector to have its internal memory re-allocated, which is possible, if you're either declaring the vector to be const or simply make sure you don't ever call resize, reserve, push_back, insert, erase and other similar methods on it), you're going to get effectively an array of small objects with a pointer inside. This is how vector is usually implemented.
It's not clear, what you mean by creating an array on compile time. Arrays declared in the manner you try to do, as well as these:
int fixed_size_array[100];
are indeed created in such a way, than their size is determined on compile time. But vectors are a different beast -- these are complex C++ objects, which manage their memory dynamically in run-time, which means that they simply cannot have a compile-time fixed size by design.
To make a long story short, it's simply not supported. There are various workarounds to get similar syntax (e.g. Boost::assign) but these don't change what you get in the executable -- they just make calling the member functions a bit simpler than a string of calls to push_back.
Maybe something like this will take you in the direction you want?
const int arr[] = { 1, 2, 3, 4, 5 };
std::vector v( arr, arr + sizeof(arr) / sizeof(*arr) );
to create a vector of vector code
std::vector< std::vector< int > > v;
calling the default no argument constructor
create a Simple vector of int
int arry[] = {1,2,3,4,5};
std::vector< int > list(arry, arry + sizeof(arry) / sizeof(int));
Thus constructed a vector from an Integer array
I'd recommend you to use push_back() Method Instead in your Scenario.
However If you just wanna get dirty you can follow the way mentioned above and create an array of std::vector< int > and pass it to the constructor of std::vector< std::vector< int > >
Check http://www.cplusplus.com/reference/stl/vector/vector/ for more Information
You might be interested on this specific Constructor overload template <class InputIterator> vector ( InputIterator first, InputIterator last, const Allocator& = Allocator() );
Neel