In order not to have to remember to delete, we are using unique_ptr to manage the memory.
We were under the impression that we can write and read in the memory, just that deletion is up to the smart pointer. However, the following code crashes on i=7220 with a segfault.
What is wrong?
#include <memory>
using namespace std;
int main() {
const uint32_t n = 40000000;
uint64_t*p = new uint64_t[n]; // this works, but we have to delete the memory or leak
for (int i = 0; i < n; i++)
p[i] = i;
unique_ptr<uint64_t> mem = make_unique<uint64_t>(n);
uint64_t* p1 = mem.get();
for (int i = 0; i < n; i++) // this crashes at i=7220
p1[i] = i;
return 0;
}
unique_ptr<uint64_t> mem = make_unique<uint64_t>(n);
This allocates one uint64_t dynamically with the value n.
You want:
unique_ptr<uint64_t[]> mem = make_unique<uint64_t[]>(n);
This specialization allocates an array of uint64_t with n elements, and has an operator[] overload which makes the below possible:
for (int i = 0; i < n; i++)
mem[i] = i;
So, there's no need to do uint64_t* p1 = mem.get();
unique_ptr<uint64_t> is a pointer to a single uint64_t value. In order to make it store an array you need to use array of unknown bound syntax:
unique_ptr<uint64_t[]> mem = make_unique<uint64_t[]>(n);
or just
auto mem{make_unique<uint64_t[]>(n)};
Note that this variant overloads operator [] so there is no need to create an intermediate raw pointer uint64_t* p1 = mem.get();
Aside from the fix other answers mentioned, you likely don't want to use make_unique here. make_unique will zero-out every single element (40 million ints!) and you immediately overwrite them. Your options are to use make_unique_for_overwrite which requires C++20, or to use new:
#include <cstdint> // for uint64_t
#include <memory> // for unique_ptr, unique_ptr<>::pointer
#include <numeric> // for iota
int main() {
auto const n = 40'000'000;
auto const p = std::unique_ptr<std::uint64_t[]>{new std::uint64_t[n]};
std::iota(p.get(), p.get() + n, 0);
}
Related
Let's assume that we have a simple struct
struct S {
int a;
int b;
int c;
}
Now we want to create an array of pointers (2d array 5x5):
S** arr = new S*[5];
for (int i = 0; i < 5; ++i)
arr[i] = new S[5];
My questions are:
Is it a correct way to dynamically allocate a memory for this array using new? Shouldn't we use sizeof(S) somewhere?
How would the code look like if using malloc instead of new? Is the code below correct?
S** arr = (S**)malloc(5 * sizeof(S));
for (int i = 0; i < 5; ++i)
arr[i] = (S*)malloc(5 * sizeof(S));
Yes, this is correct way. No, there is no need to use sizeof(S)
Your code isn't correct. Generally you shouldn't use malloc if struct S have non-trivially-copiable members, but if S satisfy that, your code should look like this:
S** arr = (S**)malloc(5 * sizeof(S*));
for (int i = 0; i < 5; ++i)
arr[i] = (S*)malloc(5 * sizeof(S));
But using malloc in C++ is considered as bad practice. And I would try to rewrite it using std::vector if you can.
And of course don't forget to clear memory with delete/free in case of using new/malloc
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");
}
We know that when using a contiguous block of memory we can easily get an iterator (here &arra[0] or arra) and pass the iterators to std::sort.
for instance:
int arra[100];
for (int i = 0; i < 100; i++) {
arra[i] = rand() % 32000;
}
for (int i = 0; i < len; i++)std::cout << arra[i]<<" ";
std::sort(arra,arra+100);
Now if I have a heap allocated array, say, like arr here:
int len;
len = 100;
int* arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = rand() % 32000;
}
I don't know whether I can get an iterator for this array, so can I use std::sort for this array at all?
if not, are there any workarounds to using std::sort on such an array?
Pointers do meet criteria of RandomAccessIterator which is required by std::sort. It doesn't matter if they point to stack memory or heap memory, as long as they point to the same (contiguous) array. So you can simply use:
std::sort(arr, arr + len);
This being said, std::vector is probably a better choice for allocating an array on the heap. It will save you the headache of managing memory on your own.
Yes, you can use std::sort in the same way in both cases, std::sort does not know or care how the memory was allocated.
In the C++ Library, Iterators are basically Fancy Pointers. As such, it is standard-compliant to just increment the pointer to the end of the array to get the "end" pointer:
#include<algorithm>
#include<iostream>
int main() {
int len;
len = 100;
int* arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = rand() % 32000;
}
//Valid, Defined Behavior that works as expected
std::sort(arr, arr + len);
//alternative, to make the code easier to read:
//auto begin = arr;
//auto end = arr + len;
//std::sort(begin, end);
for(int i = 0; i < len; i++)
std::cout << arr[i] << std::endl;
}
However, some Compilers (like Visual Studio's compiler) recognize that this kind of code is inherently unsafe, because you're required to manually supply the length of the array. As a result, they will cause a (suppressible with a Compiler flag, if you need to) Compile-time error if you try to do this, and advise you use a compiler-provided utility instead:
#include<algorithm>
#include<iostream>
int main() {
int len;
len = 100;
int* arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = rand() % 32000;
}
//MSVC Specific Code!
auto begin = stdext::make_checked_array_iterator(arr, len);
auto end = arr + len;
std::sort(begin, end);
for(int i = 0; i < len; i++)
std::cout << arr[i] << std::endl;
}
For more on this particular quick of the Visual Studio compiler, see here: https://learn.microsoft.com/en-us/cpp/standard-library/checked-iterators?view=vs-2019
Can I use std::sort on heap allocated raw arrays?
Yes.
I don't know whether I can get an iterator for this array
You can.
A pointer to element is a random access iterator for arrays. In the case of an automatic array, the array name implicitly decays into a pointer that you can use as an iterator to beginning of the array. In the case of a dynamic array, the result of new[] is already a pointer i.e. an iterator to the beginning of the array. You can get the pointer to the end using pointer arithmetic just like in your example.
The only significant difference between an array variable, and a pointer to a dynamic array regarding the use of std::sort is that you cannot use std::end or std::size with a pointer like you could with an array variable. Instead, you need to separately know the size of the array. In this case you've stored the length in the variable len.
I am trying to allocate space for vector of vector but after allocation gdb showing null in pVectorTemp_ but showing size 2
#include <iostream>
#include<vector>
using namespace std;
int main( )
{
int index1 = 2;
int index2 = 2;
vector<vector<float>*>* pVectorTemp_ = NULL;
pVectorTemp_ = new vector<vector<float>*>();
pVectorTemp_->resize(index1);
for(unsigned int i=0 ;i< index1;i++)
{
vector<float>* pvecTemp = new vector<float>();
pvecTemp->resize(index2);
(*pVectorTemp_)[index1] = (pvecTemp);
}
return 0;
}
gdb :
(gdb) pvector pVectorTemp_
elem[0]: $2 = (std::vector<float, std::allocator<float> > *) 0x0
elem[1]: $3 = (std::vector<float, std::allocator<float> > *) 0x0
Vector size = 2
Vector capacity = 2
So Am i doing anything wrong?
Inside the for loop body, you have:
(*pVectorTemp_)[index1] = (pvecTemp);
But note that the index of the for loop is i (index1 is the upper bound).
So, I think you have a typo or bug, and you may want to use i (not index1) as index inside [...].
Note also that you have a signed/unsigned mismatch, since in the loop you have unsigned int as index, and you compare that with index1, which is a signed integer.
But, anyway, your code is uselessly complicated.
You don't need to allocate all these vectors on the heap with new.
Just use automatic ("stack") allocation, e.g.:
int main()
{
int index1 = 2;
int index2 = 2;
// Your original code is commented out:
//
// vector<vector<float>*>* pVectorTemp_ = NULL;
// pVectorTemp_ = new vector<vector<float>*>();
vector<vector<float>> vectorTemp;
// pVectorTemp_->resize(index1);
// Just consider calling push_back.
for (int i = 0; i < index1; i++)
{
// vector<float>* pvecTemp = new vector<float>();
// pvecTemp->resize(index2);
// (*pVectorTemp_)[index1] = (pvecTemp);
vectorTemp.push_back(vector<float>(index2));
}
// No need for return 0 in main().
// return 0;
}
See how the code gets simplified!
(Code without comments follows.)
int main()
{
int index1 = 2;
int index2 = 2;
vector<vector<float>> vectorTemp;
for (int i = 0; i < index1; i++)
{
vectorTemp.push_back(vector<float>(index2));
}
}
As a further improvement, assuming that your C++ STL implementation provides that, you may want to use emplace_back() instead of push_back(), to build the nested vectors:
// Instead of vectorTemp.push_back(vector<float>(index2));
//
vectorTemp.emplace_back(index2);
In this case, a vector of size index2 is built directly into the vectorTemp ("outer" vector) container, without temporaries.
You may want to read also this thread on StackOverflow for further details:
push_back vs. emplace_back
These are the things I can find.
vector<vector<float>*>* pVectorTemp1 = new vector<vector<float>*>(); // (1)(4)
pVectorTemp1->resize(index1);
for (int i=0 ; i < index1; i++) { // (2)
vector<float>* pvecTemp2 = new vector<float>(); /(4)
pvecTemp2->resize(index2);
(*pVectorTemp1)[i] = (pvecTemp2); // (3)
}
Variables that differ only by trailing underscore is asking for trouble.
unsigned adds nothing, except the risk of a signed/unsigned mistake
The index should be i not index1.
It would be better to use local variables rather than heap allocation and pointers, but that would change the code too much.
Change
(*pVectorTemp_)[index1] = (pvecTemp);
with
(*pVectorTemp_)[i] = (pvecTemp);
So Am i doing anything wrong?
Yes, you are doing something wrong:
using dynamically allocation when not needed
using unnecessary raw loops
Here's a simplified version:
int main( )
{
int index1 = 2;
int index2 = 2;
std::vector<std::vector<float>> pVectorTemp_
( index1
, std::vector<float>(index2) );
}
Live demo
So how would I create an array which would contain pointers to other arrays, so that I can still access the arrays that the overall array points to? I tried this:
#include <iostream>
using namespace std;
int main (void)
{
bool (*arrays)[3], *arr1, *arr2, *arr3, *tempArr;
arr1 = new bool[2];
arr2 = new bool[2];
arr3 = new bool[2];
arr1[0] = arr2[0] = arr3[0] = 0;
arr1[1] = arr2[1] = arr3[1] = 1;
arrays[0] = arr1;
arrays[1] = arr2;
arrays[2] = arr3;
int n = 0;
while (n <= 2) {
tempArr = arrays[n];
cout << tempArr[0] << tempArr[1] << "\n";
}
}
Also, how would I make the overall array ("arrays") a pointer so that I can add new arrays to it? I made a preliminary function, but it doesn't work (note "paths" is the overall array):
void addPath (void)
{
int n = getArrayLength(paths), i = 0;
bool (*newPaths)[n + 1];
while (i < n) {
newPaths[i] = paths[i];
++i;
}
delete [] paths;
newPaths[n] = tempPath;
paths = newPaths;
}
Hopefully this isn't to confusing or absurd, and thank you for your help.
It appears that you're looking for std::vector:
#include <vector>
std::vector<std::vector<bool> > paths;
Note, however, that std::vector<bool> isn't a normal "container", and doesn't support all the operations of a normal container like vector<any_type_other_than_bool> would.
You could use malloc. Of course, that's kind of C code, not C++:
#include <cstring>
#include <cstdlib>
size_t ptrArraySize = 3;
bool** arrays = (bool**) malloc(ptrArraySize * sizeof(bool*));
Or, you could do as Jerry Coffin suggested. However, this doesn't give you a vector with pointers to vectors. It gives you a vector of vectors (so stack allocated, not on the heap). To get a vector of pointers to vectors, you could do something like:
#include <vector>
std::vector<std::vector<bool> * > ptrVector;
std::vector<bool> * vectorA = new std::vector<bool>();
vectorA->push_back(true);
ptrVector.push_back(vectorA);
Another possibility is using one of boost::scoped_array or boost::shared_array, depending on your needs.
bool (*arrays)[3] declares arrays to be a pointer to an array of 3 bools -- you want an array of 3 pointers to bools, or bool *arrays[3]. To make a pointer to that dynamically, you want just bool **arrays = new bool*[3];