I'm rather new to c++. I have been programming Java for quite some time so i apologize in advance if i use some java terminology instead of the proper c++ terminology.
I want to create a hash map(unordered_map) which maps int to pointers to a class. Now the trouble for me is to create "new" instances of the class at different addresses.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <tr1/unordered_map>
using namespace std;
class paul{
public:
paul(int n) {stuff = n;}
int stuff;
};
int main(void) {
tr1::unordered_map<int,paul*> glenn;
for(int i = 0; i < 5; i++){
paul victor(i*i);
glenn[i] = &victor;
}
for(int i = 0; i < 5; i++){
cout << i*i << "," << (*glenn[i]).stuff << "\n";
}
return EXIT_SUCCESS;
}
The code above does not work. It produces the output:
0,16
1,16
4,16
9,16
16,16
This is due to the fact that each new instance of paul gets created at the same address and thus every key in glenn will map to the same instance of paul.
So my question is now this how can i create several instances of a class at different addresses?
So my question is now this how can i create several instances of a class at different addresses?
Forget about addresses and pointers, and store objects:
tr1::unordered_map<int, paul> glenn;
for(int i = 0; i < 5; i++){
glenn[i] = paul(i*i);
}
If you really want to store pointers in your map, allocate them on the heap to extend their lifetime and prefer to use smart pointers such as std::unique_ptr or std::shared_ptr
(these smart pointers require the use of C++11 or higher).
The heap allocation will store each newly created object at a different address in memory on the heap. The smart pointers will clean up the objects when they're lifetime is up (a primitive form of garbage collection).
int main(void) {
tr1::unordered_map<int,std::unique_ptr<paul>> glenn;
for(int i = 0; i < 5; i++){
glenn[i].reset(new paul(i*i)); // prefer to use std::make_unique if/when it is available.
}
for(int i = 0; i < 5; i++){
cout << i*i << "," << (*glenn[i]).stuff << "\n";
}
return EXIT_SUCCESS;
}
Related
On a project I'm working on, I need some dynamic allocation due to the size of the used data not been known in advance. std::vector seems perfect for this use case. However, due to the software environnement, I can not use "modern" C++ in the headers. I would like to convert this vectors array to be used in fuction with compliant headers.
Quick example:
void func(int tab[][]/*Vector can not be used here*/){/*Do things*/}
int main(){
std::vector<int> vecTab[6/*Fixed, prior known, dimension*/];
//Adding a random number of values in each vector (equal number in each one)
//Transformation of vecTab
func(vecTabMod);
return 1;
}
There is a lot of similar questions on this site, none of them really adressing bi-dimensionnal arrays.
Bonus point: no reallocation, access through pointers
You'll need to copy the data pointers into a separate array so that the type and layout matches what the funciton expects. This can be done without heap allocation since the size of this array is fixed.
int* vecTabMod[6];
std::transform(std::begin(vecTab), std::end(vecTab), std::begin(vecTabMod),
[](auto& v) { return v.data(); });
func(vecTabMod);
std::vector is worst choice for this soultion!
Using dynamic arrays is better.
Anyway you can use this code:
#include <vector>
#include <iostream>
int func(uint32_t firstDimensionSize, uint32_t* secoundDimensionSizes, int** tab){
int sum = 0;
for(uint32_t i = 0; i < firstDimensionSize; i++){
for(uint32_t j = 0; j < secoundDimensionSizes[i]; j++){
sum += tab[i][j];
}
}
return sum;
}
int main(){
std::vector<int> vecTab[6];
vecTab[0].push_back(2);
vecTab[0].push_back(5);
vecTab[3].push_back(43);
// Calculate count of elements in non dynamically arrays
uint32_t firstDimensionSize = (sizeof(vecTab) / sizeof((vecTab)[0]));
uint32_t* secoundDimensionSizes = new uint32_t[firstDimensionSize];
int**tab = new int*[firstDimensionSize];
for(uint32_t i = 0; i < firstDimensionSize; i++){
secoundDimensionSizes[i] = vecTab[i].size();
tab[i] = &(vecTab[i][0]);
}
std::cout << func(firstDimensionSize, secoundDimensionSizes, tab) << std::endl;
delete[] secoundDimensionSizes;
delete[] tab;
system("pause");
}
It's possible to declare a fixed-size array of raw pointers on the stack, which can be used to dynamically allocate memory (objects) at runtime. I'm trying to replace raw pointers with smart pointers, but this pattern is failing.
The following code summarizes the problem, hope it's not too verbose:
#include <iostream>
#include <vector>
#include <memory>
const int SIZE = 10;
//older method of declaring an array of std::vector<int> pointers with
//memory leak risks, using automatic (stack-based) allocation for the
//array of pointers, dynamic (heap-based) allocation for the vectors:
std::vector<int>* arr[SIZE];
for (int i = 0; i < SIZE; i++) {
arr[i] = new std::vector<int>;
}
for (int i = 0; i < SIZE; i++) {
arr[0]->push_back(i);
}
for (int val : *arr[0]) {
std::cout << val << " "; //prints 0 - 9 as expected
}
That works as usual, but when trying to implement smart pointers I can only get a smart pointer to an array of std::vector to work, i.e.:
//declaring smart pointer to an array of std::vector<int>, which is not
//automatic (stack-based) allocation of the array
std::unique_ptr<std::vector<int>[]> arr2 (new std::vector<int>[SIZE]());
for (int i = 0; i < SIZE; i++) {
arr2[0].push_back(i);
}
for (int val : arr2[0]) {
std::cout << val << " "; //prints 0 - 9 as expected
}
As far as I can tell, this is not something smart pointers support? :
//attempting to declare an array of smart pointers to std::vector<int>
std::unique_ptr<std::vector<int>> arr3[SIZE];
for (int i = 0; i < SIZE; i++) {
std::cout << &arr3[i] << std::endl; //prints memory locations
if (arr3[i]->empty()) { //seg faults # runtime
std::cout << "empty vector\n";
}
arr3[i] = new std::vector<int>; //won't compile
}
(Please let me know if there are basic problems with this pattern as well)
In the last code block, it looks like arr3 is getting memory assigned but I cannot figure out how to use it to create a new std::vector.
//older method of declaring an array of std::vector<int> pointers with
//memory leak risks, using automatic (stack-based) allocation for the
//array of pointers, dynamic (heap-based) allocation for the vectors:
Automatic storage duration arrays don't leak. Their elements can, however. For example, when they are pointers that point to dynamically allocated elements. Smart pointers are there to replace raw pointers, so do just that - replace T* with, for example, std::unique_ptr<T>. Do not replace an array of automatic storage duration with a smart pointer - at most use std::array. I believe you are looking for something like this:
std::unique_ptr<std::vector<int>> arr3[SIZE];
// or better - std::array<std::unique_ptr<std::vector<int>>, SIZE> arr3{};
for (int i = 0; i < SIZE; i++) {
arr3[i] = std::make_unique<std::vector<int>>(); // notice the syntax...
// ... and the fact that you first allocate the vector, *then* use the ->empty()
std::cout << &arr3[i] << std::endl;
if (arr3[i]->empty()) {
std::cout << "empty vector\n";
}
}
This question already has answers here:
Freeing Memory From An Array
(2 answers)
Closed 4 years ago.
I have some problem with c++ pointer.
Here is my code:
#include <iostream>
#include <vector>
int main() {
std::vector<int*> * data = new std::vector<int*>;
for (int i = 0; i < 1000; i++) {
data->push_back(new int[100000]);
}
for (int i = 0; i < 100; i++) {
delete data->at(i);
}
data->clear();
delete data;
data = nullptr;
return 0;
}
After
std::vector<int*> * data = new std::vector<int*>;
for (int i = 0; i < 1000; i++) {
data->push_back(new int[100000]);
}
It takes 384Mb (I found it in task manager)
But after
for (int i = 0; i < 100; i++) {
delete data->at(i);
}
It still takes 346Mb
After
delete data;
data = nullptr;
It doesn't change anything
My problem is, what can I do to completely delete a pointer and free memory?
First, you probably aren't actually deleting everything. You loop only goes to 100, and you're pushing on 1000 items. Secondly, your use of data->clear() is largely pointless and irrelevant. Vectors frequently do not ever shrink themselves no matter what you do. And even if they do, you're just deleting it anyway.
Lastly, don't use new and delete, and use raw pointers sparingly. If you hadn't used them in the first place, you wouldn't have made the mistakes you did. You should've done this:
#include <iostream>
#include <vector>
#include <memory>
int main() {
using ::std::make_unique;
using ::std::unique_ptr;
typedef unique_ptr<int []> ary_el_t;
auto data = make_unique<::std::vector<ary_el_t>>();
for (int i = 0; i < 1000; i++)
{
data->push_back(make_unique<int[]>(100000));
}
data.reset();
return 0;
}
And, even if you did, you might still not get the memory back. Allocators will reuse freed space when asked for more space, but they often don't return it to the operating system.
The above code does require C++14 to work. But recent versions of Visual Studio should support that. I tested this with g++ on my Linux box, and my allocator does return memory to the OS, so I was able to verify that indeed, all the de-allocation works.
Lets say I wanted to make a vector of objects and another vector of pointers to those objects (I cannot use dynamic memory). The way I would do it is in the following example.
#include <iostream>
#include <vector>
using namespace std;
class Foo {
public:
int bar;
Foo(int x) : bar(x) {
}
};
int main () {
vector<Foo> foos;
vector<Foo*> pFoos;
for (int i = 0; i < 10; i++) {
Foo foo(i);
foos.push_back(foo);
pFoos.push_back(&foos.back());
}
for (int i = 0; i < 10; i++) {
cout << foos[i].bar << endl;
cout << pFoos[i]->bar << endl;
}
}
I think this should work because foos stores a copy of the object, and then I store the reference to the copy (because the original foo will be undefined, so I shouldn't store a reference to that). But this is what I get:
0
36741184
1
0
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
The first to numbers from pFoos are wrong. Furthermore, the large number changes every time. I don't see anything that would cause this undefined behavior. Could someone tell me what I'm doing wrong?
Adding items to a vector invalidates all previous iterators. Calling push_back on the vector may make the pointers you got from it previously invalid if the vector needs to reallocate its internal storage.
If you knew that you were never going to grow the vector again then this would work:
for (int i = 0; i < 10; i++) {
foos.push_back(Foo(i));
}
for (int i = 0; i < 10; i++) {
pFoos.push_back(&foos[i]);
}
or as commented by rodrigo:
foos.reserve(10)
for (int i = 0; i < 10; i++) {
Foo foo(i);
foos.push_back(foo);
pFoos.push_back(&foos.back());
}
for (int i = 0; i < 10; i++) {
cout << foos[i].bar << endl;
cout << pFoos[i]->bar << endl;
}
I guess this is not a good programming approach. The vector is responsible for storing objects and it may REALLOC memory to get bigger memory blobs ... So, your pointer is not valid anymore ...
vector::push_back can move elements, which is why the addresses aren't valid. You can pre-load the memory for the vector to its final size by calling reserve before you start pushing things into the vector, or you can wait until you've finished pushing things before you take their addresses.
But you say that you "cannot use dynamic memory". vector uses dynamic memory.
I have allocated an array as follows.
#include <iostream>
int main() {
const int first_dim = 3;
const int second_dim = 2;
// Allocate array and populate with dummy data
int** myArray = new int*[first_dim];
for (int i = 0; i < first_dim; i++) {
myArray[i] = new int[second_dim];
for (int j = 0; j < second_dim; j++) {
myArray[i][j] = i*second_dim + j;
std::cout << "[i = " << i << ", j = " << j << "] Value: " << myArray[i][j] << "\n";
}
}
// De-allocate array
for (int i = 0; i < first_dim; i++)
delete[] myArray[i];
delete[] myArray;
}
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
I've heard that Vectors are so much more efficient for this purpose, but I hardly know what they are and I've never used them before.
Yes, but in a very painful way. What you have to do is allocate new memory which now has your new desired dimensions, in this case 4 and 2, then copy all the contents of your matrix to your new matrix, and then free the memory of the previous matrix... that's painful. Now let's see how the same is done with vectors:
#include <vector>
using std::vector;
int main()
{
vector< vector <int> > matrix;
matrix.resize(3);
for(int i = 0; i < 3; ++i)
matrix[i].resize(2);
matrix[0][1] = 4;
//...
//now you want to make the first dimension 4? Piece of cake
matrix.resize(4);
matrix[3].resize(2);
}
HTH
edit:
some comments on your original code:
In C++ ALL_CAP_NAMES usually refer to macros (something you #define). Avoid using them in other contexts
why do you declare FIRSTDIM and SECONDDIM static? That is absolutely unnecessary. If a local variable is static it means informally that it will be the same variable next time you call the function with kept value. Since you technically can't call main a second sime this is useless. Even if you could do that it would still be useless.
you should wrire delete [] array[i]; and delete [] array; so the compiler knows that the int* and int** you're trying to delete actually point to an array, not just an int or int* respectively.
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
Yes, but it's a pain in the neck. It basically boils down to allocating a new array, just as your existing code does (hint: put it in the function and make the sizes arguments to that function) and copying compatible elements over.
Edit: One of the things that std::vector does for you is properly de-allocating you memory. In the code you have, failure to allocate one of the arrays along the 2nd dimension will result in a memory leak. A more robust solution would initialize pointers to 0 before performing any allocation. An exception block could then catch the exception and free whatever was partially allocated.
Because this code becomes complex quickly, people resort to allocating a single buffer and addressing using a stride or using a 1D array of 1D arrrays (i.e. std::vector of std::vectors).