I have a maze vector of vector of ints and a pointer line to that vector declared as follows. I also have a pointer to line that identifies each element in particular.
std::vector<std::vector<int>> maze;
auto * line = new std::vector<std::vector<int>>(maze); //pointer to maze to hold line position
auto * column = line; // pointer to element in line
maze is a vector of vectors of int that holds numbers. I'm supposed to follow a route starting from 1 and going to the next highest number(+1) until i find an exit or a dead end inside the labyrinth.
It is unclear to me how the pointer line works. My understanding is that it will hold the address of the first element in the first vector of maze. By writing line+1, the pointer will hold the address of the first element of the second vector etc. The compiler lets me write column = &line[1] and i assume column will point to the first element of line[1].
However, i didn't find a way to have line point to a specific vector in maze. I have tried the following and all cause errors:
line = &maze[i]; // make line point to i-th vector in maze
line = &(*maze.begin()); // as suggested in a stackoverflow topic, converting iterator to pointer
*line = maze[i];
The only way i didn't get an error was by writing line->begin = maze.begin(), but i want to move line to any position in maze.
What is the conceptual difference that doesn't allow me to assign line the same way i do column?
Thanks.
It is unclear to me how the pointer line works.
This line
auto * line = new std::vector<std::vector<int>>(maze);
creates a fresh new instance of std::vector<std::vector<int>>, copying the contents of maze into that new instance, and then stores a pointer to the new instance in line. line is not a pointer to maze! That would be this instead:
auto * line = &maze;
By writing line+1, the pointer will hold the address of the first element of the second vector etc.
No. line is not a pointer to an array, or to an element of an array, so you cannot increment it (well, to be precise, it can be considered as an array with one element, and so incrementing the pointer once is fine, but anything beyond that is not).
The only way i didn't get an error was by writing line->begin = maze.begin()
I'll skip the rest, because you are on the wrong track, and I have to admit that I do not completely understand what the second snippet is supposed to do.
However, i didn't find a way to have line point to a specific vector in maze
It is unclear why you want a pointer in the first place. An element of maze you get via
auto x = maze[i][j];
a reference via
auto& r = maze[i][j];
and a pointer via
auto* p = &maze[i][j];
It is not perfectly clear what you are trying to accomplish. What is clear is that your attempt with using line is flawed, because it is not a pointer to maze.
PS: If your intention was to use pointer arithmetic to navigate through the maze, then there is bad news: It won't work. At least not as easy as you hope for. A std::vector<T> stores its elements in contiguous memory. However, that memory is not inside the vector object. Hence, the Ts in a std::vector<std::vector<T>> are stored in contiguous blocks, but they are not contiguous as a whole. The outer vector holds a contiguous block of vector<T>s, and each inner vector<T> holds a separate contiguous block of ints. Collectively, the individual blocks of ints are scattered around memory.
Related
So I am doing some graphics rendering and have gotten to a point where the data being used is too high and run/loading time takes way too long. Completely my fault as I am copying a massive chucks (2+ gig) of data all over the place. Naturally I need to transition to pointers and here is the problem I face.
We have main data "vector data" and I need to access random areas (xyz points) in it.
vector<float> data{1, 2, 3, ... , 101, 102, 103, ...};
float* point1 = &data[0] //points to beginning of array (1,2,3,...)
float* point2 = &data[100] //points to middle of array (101, 102, 103,...)
Now I need to make an output array that uses both pointers, but I'm not sure how to do this. In essence I want the following.
float* outputList = point1;
outputList+3 = point2;
Such that output List = {1,2,3,101,102,103};
This wont work because I am trying to reassign the actual pointer address in the second line. The second major issue is that output list would go on after 103, and keep going till the end of the data vector. I know there are a few issues with this, but hopefully I got the idea across. Thank you for any advice.
Well, pointers point to physical address cells. When you assign outputList = point1; that means outputList will now point to the same address cell as point1. Adding a value to a pointer will move it certain amount of physical cells. You cannot state that outputList+3 = point2, because outputList already points to physical cell point1, and moving it 3 cells will point to physical cell + 3.
If you would like to have another array with values from both point1 and point2 you would have to allocate new memory and assign the right values to it. You can do that by creating another vector.
However, if you only want to use the values from point1 and point2 you could just iterate over interesting parts of original array and temporarily use the original values (without creating a new array).
This should be a comment, but I don't have enough reputation.
Take a look at std::span.
Maybe you could use a std::vector<std:span<...>>?
std::span is basically a pointer and a size.
Note that if you do something like this you lose cache locality if the data is too far apart.
I am making a game engine and need to use the std::vector container for all of the components and entities in the game.
In a script the user might need to hold a pointer to an entity or component, perhaps to continuously check some kind of state. If something is added to the vector that the pointer points to and the capacity is exceeded, it is my understanding that the vector will allocate new memory and every pointer that points to any element in the vector will become invalid.
Considering this issue i have a couple of possible solutions. After each push_back to the vector, would it be a viable to check if a current capacity variable is exceeded by the actual capacity of the vector? And if so, fetch and overwrite the old pointers to the new ones? Would this guarantee to "catch" every case that invalidates pointers when performing a push_back?
Another solution that i've found is to instead save an index to the element and access it that way, but i suspect that is bad for performance when you need to continuously check the state of that element (every 1/60 second).
I am aware that other containers do not have this issue but i'd really like to make it work with a vector. Also it might be worth noting that i do not know in advance how many entities / components there will be.
Any input is greatly appreciated.
You shouldn't worry about performance of std::vector when you access its element only 60 times per second. By the way, in Release compilation mode std::vector::operator[] is being converted to a single lea opcode. In Debug mode it is decorated by some runtime range checks though.
If the user is going to store pointers to the objects, why even contain them in a vector?
I don't feel like it is a good idea to (poor wording)->store pointers to objects in a vector. (what I meant is to create pointers that point to vector elements, i.e. my_ptr = &my_vec[n];) The whole point of a container is to reference the contents in the normal ways that the container supports, not to create outside pointers to elements of the container.
To answer your question about whether you can detect the allocations, yes you could, but it is still probably a bad idea to reference the contents of a vector by pointers to elements.
You could also reserve space in the vector when you create it, if you have some idea of what the maximum size might grow to. Then it would never resize.
edit:
After reading other responses, and thinking about what you asked, another thought occurred. If your vector is a vector of pointers to objects, and you pass out the pointers to the objects to your clients, resizing the vector does not invalidate the pointers that the vector hold. The issue becomes keeping track of the life of the object (who owns it), which is why using shared_ptr would be useful.
For example:
vector<shared_ptr> my_vec;
my_vec.push_back(stuff);
if you pass out the pointers contained in the vector to clients...
client_ptr = my_vec[3];
There will be no problem when the vector resizes. The contents of the vector will be preserved, and whatever was at my_vec[3] will still be there. The object pointed to by my_vec[3] will still be at the same address, and my_vec[3] will still contain that address. Whomever got a copy of the pointer at my_vec[3] will still have a valid pointer.
However, if you did this:
client_ptr = &my_vec[3];
And the client is dereferencing like this:
*client_ptr->whatever();
You have a problem. Now when my_vec resized, &my_vec[3] is probably no longer valid, thus client_ptr points to nowhere.
If something is added to the vector that the pointer points to and the
capacity is exceeded, it is my understanding that the vector will
allocate new memory and every pointer that points to any element in
the vector will become invalid.
I once wrote some code to analyze what happens when a vector's capacity is exceeded. (Have you done this, yet?) What that code demonstrated on my Ubuntu with g++v5 system was that std::vector code simply a) doubles the capacity, b) moves all the elements from old to the new storage, then c) cleans up the old. Perhaps your implementation is similar. I think the details of capacity expansion is implementation dependent.
And yes, any pointer into the vector would be invalidated when push_back() causes capacity to be exceeded.
1) I simply don't use pointers-into-the-vector (and neither should you). In this way the issue is completely eliminated, as it simply can not occur. (see also, dangling pointers) The proper way to access a std::vector (or a std::array) element is to use an index (via the operator[]() method).
After any capacity-expansion, the index of all elements at indexes less than the previous capacity limit are still valid, as the push_back() installed the new element at the 'end' (I think highest memory addressed.) The elements memory location may have changed, but the element index is still the same.
2) It is my practice that I simply don't exceed the capacity. Yes, by that I mean that I have been able to formulate all my problems such that I know the required maximum-capacity. I have never found this approach to be a problem.
3) If the vector contents can not be contained in system memory (my system's best upper limit capacity is roughly 3.5 GBytes), then perhaps a vector container (or any ram based container) is inappropriate. You will have to accomplish your goal using disk storage, perhaps with vector containers acting as a cache.
update 2017-July-31
Some code to consider from my latest Game of Life.
Each Cell_t (on the 2-d gameboard) has 8 neighbors.
In my implementation, each Cell_t has a neighbor 'list,' (either std::array or std::vector, I've tried both), and after the gameboard has fully constructed, each Cell_t's init() method is run, filling it's neighbor 'list'.
// see Cell_t data attributes
std::array<int, 8> m_neighbors;
// ...
void Cell_t::void init()
{
int i = 0;
m_neighbors[i] = validCellIndx(m_row-1, m_col-1); // 1 - up left
m_neighbors[++i] = validCellIndx(m_row-1, m_col); // 2 - up
m_neighbors[++i] = validCellIndx(m_row-1, m_col+1); // 3 - up right
m_neighbors[++i] = validCellIndx(m_row, m_col+1); // 4 - right
m_neighbors[++i] = validCellIndx(m_row+1, m_col+1); // 5 - down right
m_neighbors[++i] = validCellIndx(m_row+1, m_col); // 6 - down
m_neighbors[++i] = validCellIndx(m_row+1, m_col-1); // 7 - down left
m_neighbors[++i] = validCellIndx(m_row, m_col-1); // 8 - left
// ^^^^^^^^^^^^^- returns info to quickly find cell
}
The int value in m_neighbors[i] is the index into the gameboard vector. To determine the next state of the cell, the code 'counts the neighbor's states.'
Note - Some cells are at the edge of the gameboard ... in this implementation, validCellIndx() can return a value indicating 'no-neighbor', (above top row, left of left edge, etc.)
// multiplier: for 100x200 cells,20,000 * m_generation => ~20,000,000 ops
void countNeighbors(int& aliveNeighbors, int& totalNeighbors)
{
{ /* ... initialize m_count[]s to 0 */ }
for(auto neighborIndx : m_neighbors ) { // each of 8 neighbors // 123
if(no_neighbor != neighborIndx) // 8-4
m_count[ gBoard[neighborIndx].m_state ] += 1; // 765
}
aliveNeighbors = m_count[ CellALIVE ]; // CellDEAD = 1, CellALIVE
totalNeighbors = aliveNeighbors + m_count [ CellDEAD ];
} // Cell_Arr_t::countNeighbors
init() pre-computes the index to this cells neighbors. The m_neighbors array holds index integers, not pointers. It is trivial to have NO pointers-into-the-gameboard vector.
I'm new to C++ and I learned with different tutorials, in one of them I found an example of code:
I have pointed by numbers of lines, that I completely do not understand;
Does this array in array or something like that?
I can understand the second call, but what is the first doing? There is already
"coordinates[blocks[num]]", aren't there? Why need again blocks(i) ?
How do you make this part of the code easier? Did struct with this arrays
don't make easier getting value from arrays?
Thanks in advance!
// Global vars
Struct Rect {
float left;
}
Rectangle *coordinates;
int *blocks;
coordinates = new Rect[25];
blocks = new int[25];
// in method storing values
const int currentBlock = 0; //var in cycle
coordinates[currentBlock].left = column;
blocks[currentBlock] = currentBlock;
//get element method
const Rect& classA::Coords(int num) const
{
return coordinates[blocks[num]]; //(2)
}
//and calling this method like
Coords(blocks[i]); //(3)
Coords(i); //(3)
// (4)
No, not really. Lots of people will think of them as arrays and even describe them as arrays, but they're actually not. coordinates and blocks are both pointers. They just store a single address of a Rect and an int respectively.
However, when you do coordinates = new Rect[25];, for example, you are allocating an array of 25 Rects and setting the pointer coordinates to point at the first element in that array. So, while coordinates itself is a pointer, it's pointing at the first element in an array.
You can index coordinates and blocks like you would an array. For example, coordinates[3] will access the 4th element of the array of Rects you allocated. The reason why this behaves the same as arrays is because it actually is the same. When you have an actual array arr, for example, and you do arr[4], the array first gets converted to a pointer to its first element and then the indexing occurs.
No, this is not an array of arrays. What it is doing is looking up a value in one array (blocks[num]) and using that to index the next array (coordinates[blocks[num]]). So one array is storing indices into the other array.
I'll ignore that this won't compile, but in both cases you are passing an int to the Coords function. The first case looks incorrect, but might not be. It is taking the value at blocks[i], passing that to the function then using that value to index blocks to get another value, then using that other value to index coordinates. In the second case, you are just passing i, which is being used to index blocks to give you a value with which you index coordinates.
That's a broad question that I don't think I can answer without knowing exactly what you want to simplify and without seeing some real valid code.
i have a project in c++03 that have a problem with data structure: i use vector instead of list even if i have to continuously pop_front-push_back. but for now it is ok because i need to rewrite too many code for now.
my approach is tuo have a buffer of last frame_size point always updated. so each frame i have to pop front and push back. (mayebe there is a name for this approach?)
so i use this code:
Point apoint; // allocate new point
apoint.x = xx;
apoint.y = yy;
int size = points.size()
if (size > frame_size) {
this->points.erase( points.begin() ); // pop_front
}
this->points.push_back(apoint);
i have some ready-to-use code for an object pool and so i thought: it is not a great optimization but i can store the front in the pool and so i can gain the allocation time of apoint.
ok this is not so useful and probably it make no sense but i ask just to educational curiosity: how can i do that?
how can i store the memory of erased element of a vector for reusing it? does this question make sense? if not, why?
.. because erase does not return the erased vector, it return:
A random access iterator pointing to the new location of the element
that followed the last element erased by the function call, which is
the vector end if the operation erased the last element in the
sequence.
i have some ready-to-use code for an object pool ... how can i do that?
Using a vector, you can't. A vector stores its elements in a contiguous array, so they can't be allocated one at a time, only in blocks of arbitrary size. Therefore, you can't use an object pool as an allocator for std::vector.
how can i store the memory of erased element of a vector for reusing it? does this question make sense? if not, why?
The vector already does that. Your call to erase moves all the elements down into the space vacated by the first element, leaving an empty space at the end to push the new element into.
As long as you use a vector, you can't avoid moving all the elements when you erase the first; if that is too inefficient, then use a deque (or possibly a list) instead.
I'm not sure to understand what you want to do, but this should be functionnally equivalent to what you wrote, without constructing a temporary Point instance:
// don't do this on an empty vector
assert (points.size() > 0);
// rotate elements in the vector, erasing the first element
// and duplicating the last one
copy (points.begin()+1, points.end(), points.begin());
// overwrite the last element with your new data
points.back().x = xx;
points.back().y = yy;
EDIT: As Mike Seymour noted in the comments, neither this solution nor the approach proposed in the question cause any new memory allocation.
I notice this has caused confusion for several people, but after reading a couple of posts on here and the cplusplus tutorial my brain is still scrambled.
Suppose I have the following variables in a header file -
int numberOfLinePoints;
D3DXVECTOR3* line; //confused as to what it is
Then in the implementation C++ file I initialize them as follows -
//both initialized in constructor
numberOfLinePoints = 25;
line = new D3DXVECTOR3[numPoints]; //array of pointers?
What does my line variable now represent?
As far as I can tell from reading links on stackoverflow it should represent an array of pointers. I then read the following however...
(1) Pointers for Beginners
...where (A) arrays of pointers, and (B) pointers to arrays, are both discussed. This left me confused once again as they both seem to work similarly.
The fact that I define my pointers in a seperate location to where I allocate (correct?) them seems to be where my confusion stems from. Am I correct that this is an array of pointers to D3DXVECTOR3 objects?
To finish - if variable line holds information about one line segment, how would I create an array of line segments? I currently have the following -
//HEADER FILE
int numberOfLineSegments;
D3DXVECTOR3** lineCollection; //array of pointers - each of which
//points to an array of pointers?
//CPP FILE
numberOfLineSegments = 8; //constructor
for(i = 0; i < numberOfLineSegments; i++) //initialization
{ //and allocation CORRECT?
lineCollection[i] = new D3DXVECTOR*[numPoints]; //of memory for Y/N
} //lineCollection
VOID createLineSegments(startPoint, endPoint) //could return array instead
{
//pseudo to generate one line segment
while != numberOfLinePoints
line[sentinel++] = interpolate(startPoint, endPoint, time_T)
//pseudo to generate array of line segments
while != numberOfLines
lineCollection[sentinel++] = line
}
Any help is much appreciated.
Your first example:
int numberOfLinePoints;
D3DXVECTOR3* line; //confused as to what it is
Declares a simple pointer to a D3DXVECTOR3. A pointer can be initialized in two ways. First:
line = new D3DXVECTOR3;
This creates a single D3DXVECTOR3 and makes line point to that object. Second:
line = new D3DXVECTOR3[numberOfLinePoints];
This creates an array of D3DXVECTOR3s and makes line point to the first element of that array. You can then use pointer arithmetics to access other elements in that array.
If you declare you pointer as double pointer:
D3DXVECTOR3** line;
You simply create another level of indirection.
int numberOfLinePoints;
D3DXVECTOR3* line; //confused as to what it is
//both initialized in constructor
numberOfLinePoints = 25;
line = new D3DXVECTOR3[numPoints]; //array of pointers?
line is an array of D3DXVECTOR3. It would be an array of pointers if D3DVECTOR3 is itself a pointer, however. Since I don't know the C++ D3D headers very well, I'm not sure.
D3DXVECTOR3** lineCollection;
Is an array of pointers, each pointer likely being a pointer to a line (that is, an array of D3DXVECTOR3).
You have two options. Memorywise, the best would be to set each entry in lineCollection to just point to the corresponding line. This is safe if you either know the lines aren't going to change (and aren't going to be freed), or if they do change you want the changes to be reflected immedaitely inside your collection.
The other option would be to create a new array for each entry in lineCollection, and copy the points from each line into this new array.
There is no correct answer, it depends on the functionality you want.
(Attempting to answer the first part of the question as succinctly as possible without introducing other issues.)
C++ (and C) uses pointers to a single item in an array as a handle for the full array. However, some pointers don't point to items in an array! You have to make the distinction between points-to-single-item and points-to-item-in-array yourself.
int length = 8;
D3DXVECTOR3* line = new D3DXVECTOR3[length];
The new[] operator returns a pointer to the first item in the array it allocates, and this assigns that value to line. Notice that because pointers don't make the distinction of single-item vs. item-in-array:
you have to store the length separately
you have to be careful you use correct indices with pointers ("line" above)
you are better off using a "real" container type, such as:
std::deque, std::vector, etc.
std::tr1::array (aka boost::array)
(The last bullet point doesn't mean you never use pointers, you just don't use them when these containers are more appropriate.)
D3DXVECTOR3 line; // Line is a D3DXVECTOR3
D3DXVECTOR3 * line; // Line is EITHER a pointer to D3DXVECTOR3 OR an
// array of D3DXVECTOR3
D3DXVECTOR3 ** line; // Line is an array of pointers to D3DXVECTOR3 OR
// an array of array of D3DXVECTOR3
This is because an array is no specific structure in memory. It is just a bunch of D3DXVECTOR3 in a row. So pointing to the first element, and you get access to all of the others.
So, having
D3DXVECTOR3** lineCollection; // An array of pointers ORĀ an array of array!
new D3DXVECTOR[numPoints]; // A pointer to an array of D3DXVECTOR
lineCollection[i] // A pointer to an array
You initialize it by:
lineCollection[i] = new D3DXVECTOR[numPoints]; // No extra *
Yet: try to use the STL (like std::vector) instead of ugly C/Java style arrays. If you can, avoid declaring on the heap (using 'new'), but rather declaring on the stack:
D3DXVECTOR a, b, c; // a, b, and c ARE D3DXVECTOR, not pointers
std::vector<D3DXVECTOR> lines;
lines.push_back(a);
lines.push_back(b);
lines.push_back(c);
// equivalently: (you can push_back without temporaries)
std::vector<D3DXVECTOR> lines;
lines.push_back(D3DXVECTOR());
lines.push_back(D3DXVECTOR());
lines.push_back(D3DXVECTOR());
This will avoid manual memory management; it's more readable. You might not be able to always use that comfort (the way your code is organized). And if someone says something about performances, for now, don't worry. First get something working without segfaults nor memory leaks.
line = new D3DXVECTOR3[numPoints];
line holds the memory address of the first element of the array of D3DXVECTOR3.
I.e. line is a pointer to the first element of the array.
This article should clarify it.
Just look at this simple example :
case 1:
int *p = new int [N];
Here p is pointer to array of N integers and p stores starting address of the array.
case 2:
int **p = new int *[N]; //p is a pointer to pointers holding integers used for 2D array.
for(int i=0 ; i<N ; i++)
{
p[i] = new int [N]; // each element is pointer to array of integers.
}
It is applicable to all kinds of user defined types.