I need to be able to do this without using C++ smart pointers. I tried the following
double* VecToArr(std::vector<std::vector<double>> vec) {
double* newarr=new double(vec.size());
for (int i=0; i<vec.size(); i++) {
std::copy(vec[i].begin(), vec[i].end(), newarr);
newarr += vec[i].size();
}
std::cout<<"inside \n";
for (int i=0; i<vec.size(); i++) {
std::cout<<newarr[i]<<"\n";
}
return newarr;
}
int main(){
std::vector<double> x{1,2};
std::vector<double> y{3,4};
std::vector<std::vector<double>>vec;
vec.push_back(x);
vec.push_back(y);
double *arr=VecToArr(vec);
std::cout<<"outside \n";
for (int i=0; i<4; i++) {
std::cout<<arr[i]<<"\n";
}
}
But inside the VecToArr, the output is:
inside
4.54e-322 2.18e-317 4.34e-311 4.24e-314
not 1 2 3 4 like I expected
And outside it, I get the same garbage values. Why is this?
Also, since I used new to create newarr inside VecToArr, where how do I delete it? In main.cpp, after I print out the values, do I just do delete arr[]?
EDIT
When I change the function to:
double* VecToArr(std::vector<std::vector<double>> vec) {
double* newarr=new double[vec.size()*vec[0].size()];
for (int i=0; i<vec.size(); i++) {
std::copy(vec[i].begin(), vec[i].end(), newarr);
newarr += vec[i].size();
}
std::cout<<"inside \n";
for (int i=0; i<vec.size(); i++) {
std::cout<<newarr[i]<<"\n";
}
return newarr;
}
The output is now 3 4 (garbage) (garbage) instead of 1 2 3 4.
The three main problems are as others have mentioned in the comments and a bit more. Firstly, you're using the wrong type of new expression, new double(...) simply allocates memory for a single double and initializes it with the value of what was provided. You probably want new double[...] to allocate an array of the doubles.
Secondly, the size provided to this new is incorrect, only representing the first dimension of the vector (when it needs to be a sum of all the nested vectors' sizes).
Finally, you're returning newarr, which has been modified by the for loop inside the function and ends up pointing to the memory after where the allocation took place, you'll likely want to make a temporary copy of it at the start and return that instead.
With all the changes the final correct function may look like this:
double* VecToArr(std::vector<std::vector<double>> vec) {
std::size_t totalsize = 0;
for (int i=0; i<vec.size(); i++) {
totalsize += vec[i].size();
}
double* newarr=new double[totalsize];
double* walkarr=newarr;
for (int i=0; i<vec.size(); i++) {
std::copy(vec[i].begin(), vec[i].end(), walkarr);
walkarr += vec[i].size();
}
return newarr;
}
I'd also recommend passing the vector in by constant reference as currently it is being passed by value for (currently) no reason which may result in unnecessary overhead. Additionally, you should try to always use something like std::vector (or at least smart pointers) for allocation of memory rather than using new/delete directly (unless dealing with low level container implementation) as there is usually not much reason to at the expense of opening the program up to memory leaks.
There are issues with memory allocation, indexing and pointer arithmetic. I have pointed out those in your code.
#include <iostream>
#include <vector>
double* VecToArr(const std::vector<std::vector<double>>& vec) {
double* newarr=new double[vec.size() * vec[0].size()]; // <-- you have 4 elements (also notice square brackets)
double* newarr_ptr_copy = newarr;
for (int i=0; i<vec.size(); i++) {
std::copy(vec[i].begin(), vec[i].end(), newarr_ptr_copy);
newarr_ptr_copy += vec[i].size(); // don't lose track of newarr
}
std::cout<<"inside \n";
for (int i=0; i<vec.size(); i++) {
std::cout<<newarr[i]<<"\n";
}
return newarr;
}
int main(){
std::vector<double> x{1,2};
std::vector<double> y{3,4};
std::vector<std::vector<double>>vec;
vec.push_back(x);
vec.push_back(y);
double *arr=VecToArr(vec);
std::cout<<"outside \n";
for (int i=0; i<4; i++) {
std::cout<<arr[i]<<"\n";
}
delete [] arr; // make sure that you release the memory that you allocated
}
Look at this piece of code:
double* newarr=new double[vec.size()];
for (int i=0; i<vec.size(); i++) {
std::copy(vec[i].begin(), vec[i].end(), newarr);
newarr += vec[i].size();
}
A simple math fells violated here. You allocate your newarr to be the size of vec. So far so good. Now, for each element in vec you increment the pointer by vec[i].size - effectively leading to the used size of SUM(vec[i].size()). This is not right, you have undefined behavior in your program by accessing array outside of it's allocated bounds.
Please note, I also fixed a typo in your code - your original version of new double(vec.size()) allocated a single double, not an array of them.
Related
I am trying to build some .cpp code, in an XCode project. I have a very simple function that converts a matrix of data type cv::Mat (from opencv), to a simple two-dimensional c++ array.
The function looks something like this:
int* myClass::convertMatrix(cv::Mat cvmat){
int r = cvmat.rows;
int c = cvmat.cols;
int newmat[r][c];
for(int i=0; i<r; i++){
for(int j=0; j<c; j++){
newmat[i][j] = cvmat.at<int>(i, j);
}
}
return newmat;
}
I can't figure out what's wrong. I know "lvalue" refers to a specific memory location, but what does this have to do with me returning a matrix?
You're trying to return a pointer to a temporary variable inside that function.
After the function is being returned, that variable is automatically being cleaned up by the compiler.
Also, you are trying to create a stack-allocated array with parameters that are unknown at compile-time, if you had the size of the array at compile-time, you could have marked r and c as constexpr, if it didn't complain about that consider reading about VLA.
To fix those issues, just allocate the array on the heap:
int** make_2d_array(int r, int c)
{
int** arr = new int*[r];
for(int i = 0; i < r; i++)
arr[i] = new int[c];
return arr;
}
int** myClass::convertMatrix(cv::Mat cvmat){
int r = cvmat.rows;
int c = cvmat.cols;
int** newmat = make_2d_array(r, c);
for(int i=0; i<r; i++){
for(int j=0; j<c; j++){
newmat[i][j] = cvmat.at<int>(i, j);
}
}
return newmat;
}
Don't forget to delete the array when you stopped using it.
I also recommend considering using std::vector for that, so you don't have to worry about deleting the array ( way simpler ):
std::vector<std::vector<int>> newmat(r, std::vector<int>(c));
Consider the code (it has no meaningful purpose):
double* create() {
double *array = new double[100]; // 1)
for(unsigned int i=0; i<100; ++i) array[i] = i;
return array;
}
double reduce(double* array) {
double sum = 0.0;
for(unsigned int i=0; i<100; ++i) sum += array[i];
return sum;
}
int main()
{
double sum = 0.0;
for(unsigned int i=0; i<100; ++i) {
sum += reduce(create());
}
// 2)
// ...
}
Are the arrays created in 1) during the for-loop still on the heap at point 2) i.e. is some memory still being (unnecessarily) occupied at point 2)?
(I know that the example could be more minimalistic but it is really short.)
The array is still in the heap but the pointer to the array is lost. As a result there is a memory leak.
So you should split the calls of the functions introducing a variable that will store the pointer returned from the function create that then you could use the variable to free the allocated array.
That is the array with the dynamic storage duration will be destroyed when the operator delete [] will be called. Or the memory will be freed when the program will finish its execution.
I'm trying to solve this problem on variable-sized arrays but I'm getting a compilation error. Not exactly sure where I went wrong.
Problem can be accessed in this PDF
My solution attempt is as follows:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int n,q,size,elem,index,smallindex;
//input of n and q
cin>>n>>q;
//declare the array a
int* bigarr = new int[q];
//assign the individual arrays to each element of the array a
for (int i=0; i<n; ++i){
//input of size of the individual array
cin>>size;
int* smallarr = new int[size];
for (int j=0; j<size; ++j){
smallarr[j] = cin>>elem;
}
bigarr[i] = smallarr;
}
//obtain index queries
for (int k=0; k<n; ++k){
cin>>index;
cin>>smallindex;
cout<<bigarr[index][smallindex];
}
}
On this statement:
bigarr[i] = smallarr;
smallarr is an int* pointer, but bigarr is also an int*, ie an array of int, so bigarr[i] is a single int. You can't assign an int* pointer to an int value.
If you want bigarr to be an array of pointers to other arrays, you need to declare bigarr as int** instead of int*, and then use new int*[q] to allocate it.
int** bigarr = new int*[q];
Also, on this statement:
smallarr[j] = cin>>elem;
The expression cin>>elem returns an istream& reference to cin, it does not return the int value read into elem, like you are expecting. So you can't use the result of that expression directly in the assignment to smallarr[j]. You will have to read elem and assign it to smallarr in separate statements:
cin>>elem;
smallarr[j] = elem;
That said, note that your code is leaking all of the allocated arrays since there are no calls to delete[] anywhere. You need to add them:
int** bigarr = new int*[q];
...
for (int i=0; i<n; ++i){
...
int* smallarr = new int[size];
...
bigarr[i] = smallarr;
}
...
for (int i=0; i<n; ++i){
delete[] bigarr[i]; // <-- here
}
delete[] bigarr; // <-- here
Though, you really should be using std::vector instead of using new[]/delete[] manually at all (you already have #include <vector>):
std::vector<std::vector<int> > bigarr(q);
...
for (int i=0; i<n; ++i){
...
std::vector<int> smallarr(size);
for (int j=0; j<size; ++j){
...
smallarr[j] = elem;
}
bigarr[i] = smallarr;
/* alternatively:
bigarr[i].resize(size);
for (int j=0; j<size; ++j){
...
bigarr[i][j] = elem;
}
*/
}
I also see is that you are using q to allocate bigarr, but then you use n to loop through bigarr. You don't need two separate variables. Use either n or q for both tasks, and get rid of the other variable.
Unless you really intend to allocate more slots then you want to fill in. In which case, your outer loop needs to ensure that it doesn't exceed both n and q:
for (int i=0; (i<n) && (i<q); ++i){
Or:
for (int i=0; i<std::min(n,q); ++i){
I have a double array allocated by pointer to pointer.
// pointer to pointer
int **x = new int *[5]; // allocation
for (i=0; i<5; i++){
x[i] = new int[2];
}
for (i=0; i<5; i++){ // assignment
for (j=0; j<2; j++){
x[i][j] = i+j;
}
}
for (i=0; i<5; i++) // deallocation
delete x[i];
delete x;
I am trying to do this using unique_ptr:
std::unique_ptr<std::unique_ptr<int>[]> a(new std::unique_ptr<int>[5]);
for (i=0; i<5; i++)
a[i] = new int[2];
but kept getting an error saying that no operator = matches these operands. What I am doing wrong here?
You cannot assign a int* to a std::unique_ptr<int[]>, that is the cause for your error. The correct code is
a[i] = std::unique_ptr<int[]>(new int[2]);
However, piokuc is correct, that it is highly unusual to use unique_ptr for arrays, as that's what std::vector and std::array are for, depending on if the size is known ahead of time.
//make a 5x2 dynamic jagged array, 100% resizable any time
std::vector<std::vector<int>> container1(5, std::vector<int>(2));
//make a 5x2 dynamic rectangular array, can resize the 5 but not the 2
std::vector<std::array<int, 2>> container1(5);
//make a 5x2 automatic array, can't resize the 2 or 5 but is _really fast_.
std::array<std::array<int, 2>, 5> container;
All of these can be initialized and used just the same as the code you already had, except they're easier to construct, and you don't have to destroy them.
If you do not have the luxury of using a std::array or a std::vector instead of a dynamically allocated array, you can use a std::unique_ptr for a two-dimensional array in C++11 as follows:
std::unique_ptr<int*, std::function<void(int**)>> x(
new int*[10](),
[](int** x) {
std::for_each(x, x + 10, std::default_delete<int[]>());
delete[] x;
}
);
The unique_ptr declaration takes care of allocating the row dimension of the array. The trailing () in new int*[10]() ensures that each column pointer is initialized to nullptr.
A for loop then allocates the column arrays:
for (size_t row = 0; row < 10; ++row) {
(x.get())[row] = new int[5];
}
When the unique_ptr goes out of scope, its custom deleter lambda function takes care of deleting the column arrays before deleting the row array. The for_each expression uses the default_delete functor.
for (i=0; i<5; i++) // deallocation
delete x[i];
delete x;
NO NO NO NO
delete [] x[i];
delete [] x;
// yo
The only reasons I can think of to use std::unique_ptr (or say boost::scoped_array) over std::vector for holding arrays are usually not applicable...
1) it saves 1 or 2 pointers worth of memory, depending on if you know what the size of all the arrays is [irrelevant unless you have a massive number of very small arrays]
2) in case you are just passing the array into some function that expects a C style array or raw pointer, it may feel like a more natural fit. std::vector IS guaranteed to be on sequential storage though, so passing (a.empty() ? nullptr : &a[0], a.size()) into such a function is 100% legit as well.
3) standard containers in MSVC debug mode are "checked" by default and very slow, which might be annoying when doing scientific programming on large datasets.
Your code is effectively manipulating an array of arrays of int.
In C++ you would normally want to implement it as:
std::vector<std::vector<int> > x;
This is not a good case for unique_ptr. Also, you should not need to use pointers to unique_ptr and allocate unique_ptr objects dynamically. The whole point of unique_ptr is to eliminate usage of pointers and to provide automatic allocation and deallocation of objects.
#include <iostream>
#include <memory>
#define print(x) std::cout << x
#define println(x) std::cout << x << std::endl
int main() {
std::unique_ptr<std::unique_ptr<int[]>[]> arr(new std::unique_ptr<int[]>[2]());
for (int i = 0; i < 2; i++)
{
arr[i] = std::make_unique<int[]>(5);
for (int j = 0; j < 5; j++) {
arr[i][j] = j;
println(arr[i][j]);
}
println(arr[i]);
}
}
An example further up inspired me for this solution
size_t k = 10;
std::unique_ptr<int*, std::function<void(int**)>> y(new int*[k](),
[](int** x) {delete [] &(x[0][0]);
delete[] x;});
// Allocate the large array
y.get()[0] = new int[k*10];
// Establish row-pointers
for (size_t row = 0; row < k; ++row) {
(y.get())[row] = &(y.get()[0][0]);
}
Here all dimensions can be dynamic and you can wrap it inside a class and expose an operator[]. Also the memory is allocated in a contiguous manner and you can easily introduce an allocator, which allocates aligned memory.
for (i=0; i<5; i++) // deallocation
delete x[i];
delete x;
It is a common mistake here.
x[i] is an array so you have to delete each array first using delete[]
Then you can delete you array of int* by using delete[]
Correct desallocation would be:
for (i=0; i<5; i++)
delete[] x[i]; //desallocate each array of int
delete[] x; //desallocate your array of int*
x = nullptr; //good practice to be sure it wont cause any dmg
I am making a C++ program that checks if given aray is a latin square. I need to use a dynamic multi-dimensional array that stores given latin square. But I cant pass the array to a function that does the checking...
Currently I have such code for calling the function:
int squaretest(int **p, int n, int sum) {
//some code
};
And this code is for creating the array:
int main() {
//some code. n - length of one row, sum - sum of elements in one row.
int a;
int **lsquare;
lsquare = new int*[n];
for (int i=0;i<=n-1;i++) for (int j=0;j<=n-1;j++) {
cin >>a;
lsquare[i][j] = a;
}
blocktest(lsquare,n,sum);
//some code
};
The code compiles (i am using Geany IDE and G++ compiler) but when I run it in terminal, after the first imput, that has to be stored in block[0][0] I get Segmentation fault error. What's wrong with my code and what is the correct sollution?
To be able to do that.. You actually need to do this:
int **lsquare = new int*[n];
for (int i=0; i<n; ++i)
lquare[i] = new int[n];
for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
cin >> lsquare[i][j];
blocktest(lsquare,n,sum);
The better system would be to do:
int *lsquare = new int[n*n];
for (int i=0; i<n; ++i)
for (int j=0; j<n; ++j)
cin >> lsquare[i + j*n];
blocktest(lsquare, n, sum);
You forgot to allocate memory for second dimension of the matrix.
int **lsquare;
lsquare = new int*[n];
for (int i=0; i<n; ++i){
lsquare[i] = new int[n];
....}
nobody writes
for (int i=0;i<=n-1;i++){...}
Do instead
for (int i=0; i<n; ++i){...}
You have an array of pointers in lsquare.
You might want to just do something like:
lsquare = new int[n * n];
That way you can then fill in this square, but the type is then:
int *lsquare
What you are actually creating an array of arrays. Not only do you need to allocate the array of arrays using new, but also you must allocate all n arrays. You'll want to have the outer loop of your nested for loop allocate each of the n sub-arrays.
lsquare = new int*[n];
for (int i=0;i<=n-1;i++)
{
lsquare[i] = new int[n];
for (int j = 0;j<=n-1;j++)
{
//...
You made yourself a pointer pointer that can be used as a matrix, allocated one row for it, then proceeded to act like you'd allocated an entire n*n matrix. You will indeed get a segfault if you run that.
You need to allocate enough space for n*n elements, not just n of them.
A less error-prone solution might be to use a std::vector of std::vectors.
You have to allocate space for the second dimension too, add this after you allocate lsquare:
for(int i = 0; i < n; ++i)
{
lsquare[i] = new int[n];
}