storing addresses of std::list elements; memory - c++

I am creating std::list of struct elements. With a certain criterion, I want to store addresses of few elements (because those addresses don't change(?)) from the list into std::vector for quick access in another usage. An example of the things is given below
#include <iostream>
#include <vector>
#include <list>
struct Astruct{
double x[2];
int rank;
};
int main(int argc, char *argv[]) {
std::list<Astruct> ants;
std::vector< Astruct* > ptr;
for (auto i = 0; i != 20; ++i) {
Astruct local;
local.x[0] = 1.1;
local.x[1] = 1.2;
local.rank = i;
// put in list
ants.push_back(local);
// store address of odd numbers
// rather than temperory address, permenent address from list is needed
if(local.rank %2 == 0) ptr.push_back(&local);
}
// print the selected elements using addresses from the list
for(int num = 0; num != ptr.size(); num++){
Astruct *local;
local = ptr.at(num);
std::cout << " rank " << local->rank << "\n";
}
/*
// quick way to check whether certain address (eg 3rd element) exists in the std::vector
std::list<Astruct>::iterator it = ants.begin();
std::advance(it , 2);
for(int num = 0; num != ptr.size(); num++){
if(it == ptr.at(num)) std::cout << " exists in vector \n " ;
}
*/
// print memory in bytes for all variables
std::cout << " sizeof Astruct " << sizeof(Astruct) << "\n";
std::cout << " sizeof ants " << sizeof(ants) << "\n";
std::cout << " sizeof ptr " << sizeof(ptr) << "\n";
}
What's the way to access an address of a particular element from the list?
Is it efficient method to add elements to list? (in first for loop)
What is the quickest way to check whether certain address exists in the vector? (shown in comment block)
How to determine the memory size in bytes for different variables here? (end of the code)
Thanks.

What's the way to access an address of a particular element from the list?
address=&(*iterator);
Is it efficient method to add elements to list? (in first for loop)
the first loop does not use the list at all! (Ah, OK, after edition it does)
all the addresses which are stored in the vector refer to a local variable which disappears after each iteration; this is undefined behaviour (very probably, but nothing is certain, all these addresses are the same)
What is the quickest way to check whether certain address exists in the vector? (shown in comment block)
usualy std::find() from <algorithm> is suitable.
How to determine the memory size in bytes for different variables here? (end of the code)
std::cout << " sizeof Astruct " << sizeof(Astruct) << "\n"; is OK
std::cout << " sizeof ants " << size(ants)*sizeof(Astruct) << "\n"; is an approximation since we don't know the overhead of the list and its nodes
std::cout << " sizeof ptr " << size(ptr)*sizeof(Astruct *) << "\n"; is an approximation since we don't know the overhead of the vector

Related

How c++ manages the memory of a container in class?

In c++, when all the memory allocated to a container (say vector) is used up (and we are trying to add one more element), the memory will be reallocated. However, I was wondering that how class in c++ manages the memory for containers.
For example, I run the following code:
#include <iostream>
#include <vector>
class Test{
public:
int i = 0;
std::vector<int> v;
};
int main(){
Test t;
std::cout << "Address of t: " << &t << ", capacity of vector: " << t.v.capacity() << ", size of vector: " << t.v.size() << ", address of vector: " << &(t.v) << std::endl;
t.v.push_back(1);
std::cout << "Address of t: " << &t << ", capacity of vector: " << t.v.capacity() << ", size of vector: " << t.v.size() << ", address of vector: " << &(t.v) << std::endl;
t.v.push_back(2);
std::cout << "Address of t: " << &t << ", capacity of vector: " << t.v.capacity() << ", size of vector: " << t.v.size() << ", address of vector: " << &(t.v) << std::endl;
return 0;
}
And the output is:
Address of t: 0x61fee8, capacity of vector: 0, size of vector: 0, address of vector: 0x61feec
Address of t: 0x61fee8, capacity of vector: 1, size of vector: 1, address of vector: 0x61feec
Address of t: 0x61fee8, capacity of vector: 2, size of vector: 2, address of vector: 0x61feec
The address of the vector is not changed. Does it mean the c++ uses a pointer to represent each data member (so address 0x61feec actually points to the address of the vector)?
The address of the vector is not changed.
Correct, because the vector itself is not moving around in memory.
Does it mean the c++ uses a pointer to represent each data member (so address 0x61feec actually points to the address of the vector)?
Everything in memory has an address.
The std::vector class internally contains a data member that is a pointer to an array of elements. The vector::size() method reports the number of valid elements in the array, while the vector::capacity() method reports the maximum number of elements the array is allocated to hold. The vector (re-)allocates that array dynamically as needed, ie whenever the size() is equal to the capacity() when adding new elements.
Nothing in your example code is printing the address of that array itself. The vector::data() method returns a pointer to that array. Add that pointer to your logging, and you will see it change value as the capacity() changes over time, eg:
void log(const Test &t)
{
std::cout << "Address of t: " << &t
<< ", capacity of vector: " << t.v.capacity()
<< ", size of vector: " << t.v.size()
<< ", address of vector: " << &(t.v)
<< ", address of vector data: " << t.v.data()
<< std::endl;
}
int main(){
Test t;
log(t);
for(int i = 1; i <= 50; i++)
{
t.v.push_back(i);
log(t);
}
return 0;
}
The memory is embedded into the containing class. Let's look at an easy example:
struct myvector {
size_t size;
void* data;
}
class Test {
myvector v;
}
In this case, new objects of class Test will be allocated with sizeof(size_t)+sizeof(void*) bytes.
Now when it comes to resizing the vector, all that is done, is a realloc() on the memory pointed to by data.
Of course, the std::vector implementation is far more complicaten than that, but I think you get the idea.

What is the relationship between an array and its address?

The following code:
#include<iostream>
int main (void) {
int lista[5] = {0,1,2,3,4};
std::cout << lista << std::endl;
std::cout << &lista << std::endl;
std::cout << lista+1 << std::endl;
std::cout << &lista+1 << std::endl;
std::cout << lista+2 << std::endl;
std::cout << &lista+2 << std::endl;
std::cout << lista+3 << std::endl;
std::cout << &lista+3 << std::endl;
return (0);
}
Outputs:
0x22ff20
0x22ff20
0x22ff24
0x22ff34
0x22ff28
0x22ff48
0x22ff2c
0x22ff5c
I understood that an array is another form to express a pointer, but we cannot change its address to point anywhere else after declaration. I also understood that an array has its value as the first position in memory. Therefore, 0x22ff20 in this example is the location of the array's starting position and the first variable is stored there.
What I did not understand is: why the other variables are not stored in sequence with the array address? I mean, why lista+1 is different from &lista+1. Should not they be the same?
In pointer arithmetic, types matter.
It's true that the value is the same for both lista and &lista, their types are different: lista (in the expression used in cout call) has type int* whereas &lista has type int (*)[5].
So when you add 1 to lista, it points to the "next" int. But &lista + 1 points to the location after 5 int's (which may not be a valid).
Answering the question as asked:
std::cout << &lista+1 << std::endl;
In this code you take the address of array lista and add 1 to obtained answer. Given the sizeof of the array is sizeof(int) * 5, which means when you increment a pointer to it by 1 you add sizeof(int) * 5 to the pointer address, you end up with a number you see.

Do items in a std::map stay at the same address forever?

Take the following simple program:
struct Foo
{
int x;
int y;
int z;
string s;
};
int main()
{
Foo f1 = { 42,21,11, "Hello world" };
std::map<int, Foo> foomap;
foomap[400] = f1;
Foo* ptr = &foomap[400]; // cache a pointer to the element we just inserted.
cout << ptr->x << " " << ptr->y << " " << ptr->z << " " << ptr->s << std::endl;
// fill the map up with a bunch of other random items at random indices
for (int x = 0; x < 10000; x++)
{
int i = rand();
Foo f = { rand(), rand(), rand(), "Another string" };
if (foomap.find(i) == foomap.end())
{
foomap[i] = f;
}
}
Foo* ptr2 = &foomap[400];
cout << "f1 insert location has " << ((ptr == ptr2) ? "not changed" : "changed") << std::endl;
cout << ptr->x << " " << ptr->y << " " << ptr->z << " " << ptr->s << std::endl;
return 0;
}
So the program above caches a pointer to an item in the map. Then adds a whole lot more items into the map, and then validates if the first inserted item has changed location.
I was somewhat surprised when I ran it. The cached pointer stays intact:
42 21 11 Hello world
f1 insert location has not changed
42 21 11 Hello world
I would have assumed that as the map grows with respect to the number of items in it, the implementation might move items around - just like std::vector absolutely does.
So my question is this: Are items inserted into a map guaranteed to be at the same address as long as it's not removed from the map or replaced? Or is this implementation specific?
Yes, insertion / emplacement operations on map never invalidate iterators or references to existing items.
26.2.6 Associative containers [associative.reqmts]
9 The insert and emplace members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.

What's a practical use-case for "address of array"?

(Disclaimer: Pointers in C++ is a VERY popular topic and so I'm compelled to believe that someone before me has already raised this point. However, I wasn't able to find another reference. Please correct me and feel free to close this thread if I'm wrong.)
I've come across lots of examples that distinguish between pointer to first element of array and pointer to the array itself. Here's one program and its output:
//pointers to arrays
#include <iostream>
using namespace std;
int main() {
int arr[10] = {};
int *p_start = arr;
int (*p_whole)[10] = &arr;
cout << "p_start is " << p_start <<endl;
cout << "P_whole is " << p_whole <<endl;
cout << "Adding 1 to both . . . " <<endl;
p_start += 1;
p_whole += 1;
cout << "p_start is " << p_start <<endl;
cout << "P_whole is " << p_whole <<endl;
return 0;
}
Output:
p_start is 0x7ffc5b5c5470
P_whole is 0x7ffc5b5c5470
Adding 1 to both . . .
p_start is 0x7ffc5b5c5474
P_whole is 0x7ffc5b5c5498
So, as expected, adding 1 to both gives different results. But I'm at a loss to see a practical use for something like p_whole. Once I have the address of the entire array-block, which can be obtained using arr as well, what can I do with such a pointer?
For single arrays, I don't think there's much point to it. Where it becomes useful is with multi-dimensional arrays, which are arrays of arrays. A pointer to one of the sub-arrays is a pointer to the row, and incrementing it gets you a pointer to the next row. In contrast, a pointer to the first element of the inner array is a pointer to a single element, and incrementing it gets you the next element.
int (*)[10] is a "stronger" type than int* as it keeps size of the array,
so you may pass it to function without passing additional size parameter:
void display(const int(*a)[10]) // const int (&a)[10] seems better here
{
for (int e : *a) {
std::cout << " " << e;
}
}
versus
void display(const int* a, std::size_t size) // or const int* end/last
{
for (std::size_t i = 0; i != size; ++i) {
std::cout << " " << a[i];
}
}

C++ Structs in arrays

Am i doing this right, I want a map with a Integer as key, and struct as value. What is the easiest way to, say I want the object at 1. How do I retrieve the value of isIncluded? The last two lines in the code, I tried doing it, but then I realized I donĀ“t really know what is the way to retrieving values of structs in a numbered Map array.
Do I need to call cells.get(1) and assign that to a new temporarely struct to get its values?
/** set ups cells map. with initial state of all cells and their info*/
void setExcludedCells (int dimension)
{
// Sets initial state for cells
cellInfo getCellInfo;
getCellInfo.isIncluded = false;
getCellInfo.north = 0;
getCellInfo.south = 0;
getCellInfo.west = 0;
getCellInfo.east = 0;
for (int i = 1; i <= (pow(dimension, 2)); i++)
{
cells.put(i, getCellInfo);
}
cout << "Cells map initialized. Set [" << + cells.size() << "] cells to excluded: " << endl;
cells.get(getCellInfo.isIncluded);
cells.get(1);
}
the Map, is declared as an private instance variable like this:
struct cellInfo {
bool isIncluded;
int north; // If value is 0, that direction is not applicable (border of grid).
int south;
int west;
int east;
};
Map<int, cellInfo> cells; // Keeps track over included /excluded cells
From the documentation for Map, it appears that .get() returns a ValueType.
You would use it thus:
// Display item #1
std::cout << cells.get(1).isIncluded << "\n";
std::cout << cells.get(1).north << "\n";
Or, since the lookup is relatively expensive, you could copy it to a local variable:
// Display item #1 via initialized local variable
cellInfo ci = cells.get(1);
std::cout << ci.isIncluded << " " << ci.north << "\n";
// Display item #2 via assigned-to local variable
ci = cells.get(2);
std::cout << ci.isIncluded << " " << ci.north << "\n";
My best advice is to use the standard library's std::map data structure instead:
// Expensive way with multiple lookups:
std::cout << cells[1].isIncluded << " " << cells[1].north << "\n";
// Cheap way with one lookup and no copies
const cellinfo& ci(maps[1]);
std::cout << ci.isIncluded << " " << ci.north << "\n";