Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I am a C/C++ newbie, so sorry if my question seems straightforward.
It has always been claimed that pointers in C++ are useless. See for example the answer from Konrad Rudolph here https://softwareengineering.stackexchange.com/questions/56935/why-are-pointers-not-recommended-when-coding-with-c
Below I have an example for which I am wondering how can I replace the C code by a C++ code without using any pointers:
double *A;
double **a;
A=new(std::nothrow) double[4];
a=new(std::nothrow) double*[2];
for (unsigned int q=0, k=0; k < 2; k++)
{
a[k]=A + q;
q+=2;
}
delete[] A;
delete[] a;
The programmer codes up as above because he/she needs the pointer a to point to the pointer A so that when modifying the variable to which A points, he/she does not to modify a.
Sometimes, the programmer does a for loop with a[k] from k={0,1,2,3}, and sometimes he does a double for loop a[i][j] from i,j={0,1}.
How can I replace this by a C++ code without using pointers?
Some important clarity: what you're being advised is to not use Raw, Owning Pointers. It's perfectly fine to use Non-Owning Raw Pointers iff you know, as a fact, that you're not responsible for deleteing said memory; or Owning Smart Pointers iff you are responsible for said memory, but deleteing will be handled by the RAII principles of the smart pointer class.
So let's consider what's happening in your code:
A represents ownership over a runtime-sized array of doubles.
a represents ownership over a runtime-sized array of non-owning pointers to doubles, all of which will come from A.
Simply creating an array of objects is either best represented by std::array, for compile-time-sized arrays, or std::vector, for runtime-sized arrays. So we'll need the latter. This is easy to construct:
std::vector<double> A(4);//Array of 4 doubles.
Since a will contain non-owning pointers to A, which we know will outlive a, it's perfectly fine to use raw pointers inside this vector:
std::vector<double*> a(2);
Then, we assign into it, just like your code was already doing:
//Use size_t for sizes in C++. Always, always, always.
for (size_t q = 0, k = 0; k < 2; k++){
a[k] = A + q;//Uh oh, this doesn't compile!
q += 2;
}
Ah, hmm. A isn't a raw pointer anymore. Well, we'll need to use a member function of std::vector to get the raw pointer.
//Use size_t for sizes in C++. Always, always, always.
for (size_t q = 0, k = 0; k < 2; k++){
a[k] = A.data() + q;//There we go.
q += 2;
}
Finally, because our memory is RAII-managed, we don't need to delete this memory afterwards:
//No longer needed
//delete[] A;
//delete[] a;
So the final code will end up looking like this:
std::vector<double> A(4);
std::vector<double*> a(2);
for (size_t q = 0, k = 0; k < 2; k++){
a[k] = A.data() + q;
q += 2;
}
This code is nearly identical to the C-style code you wrote originally, and is much easier to read and maintain. The only difference is the small amount of overhead in std::vector, which the compiler can optimize away for the final program.
If you want code which literally emulates the behavior of your original code, this would be the result. I don't recommend it, because it's more complicated than you need, and limits how the code can be used, but if you just want the direct port (or just want to see how Smart Pointers fit into this kind of problem), here it is:
std::unique_ptr<double[]> A = std::make_unique<double[]>(4);
std::unique_ptr<double*[]> a = std::make_unique<double*[](2);
for (size_t q = 0, k = 0; k < 2; k++){
a[k] = A.get() + q;
q += 2;
}
One of the primary uses of pointer-to-pointer in C is to return a pointer value:
error_t Allocate Object(Object ** ptr);
While the same will work in C++ it can be made somewhat more intuitive by making the function take a reference-to-pointer instead of pointer-to-pointer:
error_t AllocateObject(Object *& ref);
This way the calling code can simply pass the pointer variable (instead of needing to use & to take its address) and the function definition can simply assign to the parameter (rather than needing to dereference it with *).
The modern C++ equivalent of your example code would use smart pointers for ownership, and iterators to access array elements:
#include <array>
#include <memory>
int main()
{
// Define our types:
using A_array = std::array<double, 4>;
using A_iterator = A_array::iterator;
// Make smart pointers to manage ownership for us:
auto const A = std::make_unique<A_array>();
auto const a = std::make_unique<std::array<A_iterator, 2>>();
// Normally, we'd just put these in automatic storage, as
// they are small, and don't outlive the function scope:
// A_array A;
// std::array<A_iterator, 2> a;)
{
// Populate a with iterators to A's elements
auto target = A->begin();
for (auto& element: *a) {
element = target;
target += 2;
}
}
// No need for delete[] at end of function or at any other
// return statement.
}
Related
I am currently working with code that at the moment requires me to make an array of vectors (I am new to C++ - if this is an absolutely terrible idea, I would greatly appreciate the feedback).
Let's say I allocate memory on the heap for my vectors like so:
#include <iostream>
#include <vector>
#include <random>
int main() {
typedef std::vector<double> doubleVec;
long N = 1000;
long M = 1000;
doubleVec *array = new doubleVec[N];
for (long i = 0; i < N; i++) {
doubleVec currentVec = array[i];
currentVec.resize(M);
for (long j = 0; j < M; j++)
currentVec[j] = std::rand();
}
// ... do something with the data structure
delete [] array;
}
When I've done everything I need to do with the data, how should I safely deallocate this data structure?
NOTE: There were other things I did wrong in my inital post that I didn't intend to be the focus of the discussion (uninitialized variables, didn't resize vectors, etc). I fixed those now. Thank you all for pointing those out.
f this is an absolutely terrible idea, I would greatly appreciate the feedback).
Yes, this is a terribly bad idea. To be specific, owning bare pointers are a bad idea. Instead of manually allocating a dynamic array, it is usually better to use a container such as std::vector.
How to safely deallocate a heap-allocated array of vectors?
By using a vector instead of manual dynamic array. In this case, a simple solution is to use a vector of vectors.
A potentially better solution would be to allocate a single flat vector of doubles of size 1000*1000 where elements of each "subvector" is after another. This requires a bit of simple math to calculate the index of the sub vectors, but is in most use cases faster.
Other notes:
typedef std::vector<double> doubleVec;
Avoid obfuscating the program by hiding type names like this.
for (long j; j < M; j++)
^^^^^^
You leave this variable uninitialised. When the indeterminate value is used later, the behaviour of the program is undefined.
Furthermore, you forgot to include the standard headers which define std::vector and std::rand.
I got a seg fault
See the other answer regarding you not actually adding any elements to the vectors that are in the array. This, and the uninitialised variables are the most likely reason for your segfault depending on what "do something" does.
The problem is not in deallocating but in each vector allocation. Where in your code do you use the M value (except while accessing the elements)? There are other problems in your code, so the quick fix is:
for (long i; i < N; i++) {
doubleVec ¤tVec = array[i];
currentVec.resize(M);
for (long j; j < M; j++)
currentVec[j] = std::rand();
}
Pay special attention that currentVec is a reference: otherwise no changes would be stored in the array.
Anyway, the main question everybody would have is: why do you need to have an array of vectors?.. The vector of vectors is a much more elegant solution.
Update: I've missed the fact that you have forgotten to initialize both i and j. In addition to the advice to initialize them I would recommend to use the auto keyword that would make it impossible to leave the variable uninitialized:
for (auto i=0UL; i < N; i++) {
doubleVec ¤tVec = array[i];
currentVec.resize(M);
for (auto j=0UL; j < M; j++)
currentVec[j] = std::rand();
}
0UL means zero of the type unsigned long.
I'm trying to copy the data present in an array of pointers to another one.
I have very few knowledge in C++, but some in higher level languages.
Here is a sample code of what I've achieved so far (simplified version):
#define MAX_ACTIVE_MODES 3
myStruct_t priorities1[MAX_ACTIVE_MODES];
myStruct_t *priorities2[MAX_ACTIVE_MODES];
for (unsigned short i = 0; i < MAX_ACTIVE_MODES; ++i) {
priorities2[i] = (myStruct_t*)malloc(sizeof(myStruct_t));
memcpy(priorities2[i], &priorities1[i], sizeof(myStruct_t));
}
// ...
delete[] *priorities2;
It's easier for me to have a non pointer var for priorities1 and have one for priorities2 because I'm passing it to a sort function.
When I search for solutions, there's never the case of type *var[] and I don't get why.
Even though your question is tagged c++, I assume that you are programming in C based on your use of malloc.
First you don't need to use memcpy to copy structs.
*priorities2[i] = priorities1[i];
should be equivalent to
memcpy(priorities2[i], &priorities1[i], sizeof(myStruct_t));
Second, you don't have to create copies of the elements in priorities1[]. Just have the pointers in priorities2[] point to the elements in priorities1[]:
for (size_t i = 0; i < MAX_ACTIVE_MODES; ++i)
{
priorities2[i] = &priorities1[i];
}
As long as you don't access priorities2 beyond the lifetime of priorities1, no malloc or free is needed.
I was wondering if this is the proper way create a temporary array using pointers in a class. Part of my problem says this:
getMedian – returns the median value of the array. See Chapter 10 Programming Challenge 6 (p. 693) for a discussion of the term median. Taking the median will require a sorted array. You will need to create a temporary array to sort the values (to preserve the ordering of numbers). Do not sort the private member numbers array. Dynamically allocate/deallocate a temporary array in your getMedian function to determine the median.
My code:
double Statistics::getMedian() const
{
int tempArray[length];
for (int k = 0; k < length; k++){
tempArray[k] = numbers[k];
}
bubbleSort(tempArray);
return 0;
}
Before obviously doing the median part and a proper return statement, is this.
How you properly copy over a temporary array to alter for this problem? I don't think it is because I'm not properly allocating or deallocating anything, but I don't understand how to create a temporary array without altering the original.
Your assignment says you are to allocate/deallocate the array dynamically. That means (in C++) using new and delete. Since you want an array, you should use array space allocator operators new[] and delete[].
double Statistics::getMedian() const
{
int *tempArray = new int[length];
for (int k = 0; k < length; k++){
tempArray[k] = numbers[k];
}
// work with tempArray
delete[] tempArray;
return 0; // or the median
}
EDIT:
As suggested in the comment below, modern (C++11 and newer) way is to use smart pointers. That would mean your code could look like this.
#include <memory>
double Statistics::getMedian() const
{
std::unique_ptr<int[]> tempArray (new int[length]);
for (int k = 0; k < length; k++){
tempArray[k] = numbers[k];
}
// work with tempArray like you would with an old pointer
return 0; // or the median
// no delete[], the array will deallocate automatically
}
Check unique_ptr template class for more details. Note that this solution might not be what your professor wants, especially when the assignment talks about deallocation.
Inside a function, I make a 2d array that fills itself from a text file and needs to get returned to main. The array stays a constant size through the whole program.
I know this is something that gets asked a lot, but I always seem to get one of two answers:
Use std::vector or std::array or some other STD function. I don't really understand how these work, is there any site actually explaining them and how they act compared to normal arrays? Are there any special #includes that I need?
Or
Use a pointer to the array, and return the pointer. First, on some of the answers to this it apparently doesn't work because of local arrays. How do I tell when it does and doesn't work? How do I use this array back in the main function?
I'm having more trouble with the concept of pointers and std::things than with the actual code, so if there's a website you know explains it particularly well, feel free to just put that.
Not necessarily the best solution, but the easiest way to get it working with vectors. The advantages are that you don't need to delete memory (happens automatically) and the array is bounds-checked in debug mode on most compilers.
#include <vector>
#include <iostream>
using array2D = std::vector< std::vector< int > >;
array2D MyFunc(int x_size, int y_size)
{
array2D array(y_size, vector< int >(x_size));
int i = 0;
for (int y = 0; y < array.size(); y++)
{
for (int x = 0; x < array[y].size(); x++)
{
// note the order of the index
array[y][x] = i++;
}
}
return array;
}
int main()
{
array2D bob = MyFunc(10, 5);
for (int y = 0; y < bob.size(); y++)
{
for (int x = 0; x < bob[y].size(); x++)
{
cout << bob[y][x] << "\n";
}
}
}
Live example:
http://ideone.com/K4ilfX
Sounds like you are new to C++. If this is indeed the case, I would suggest using arrays for now because you probably won't be using any of the stuff that STL containers give you. Now, let's talk about pointers.
You are correct that if you declare a local array in your function, the main function won't have access to it. However, this is not the case if you dynamically allocate the array using the new keyword. When you use new to allocate your array, you essentially tell the compiler to reserve a chunk of memory for your program. You can then access it using a pointer, which is really just the address of that chunk of memory you reserved. Therefore, instead of passing the entire array to the main function, all you need to do is pass a pointer (address) to that array.
Here are some relevant explanations. I will add to them as I find more:
Dynamic Memory
The easiest way to create a 2d array is as follows:
char (*array)[10];
array = new array[5][10];
Two dimensional arrays can be tricky to declare. The parenthesis above in the variable declaration are important to tell the compiler array is a pointer to an array of 10 characters.
It is really essential to understand pointers with C and C++ unless using the std:: collections. Even then, pointers are widely prevalent, and incorrect use can be devastating to a program.
I am writing a C++ class that uses some fixed arrays, as well as some dynamically allocated arrays.
I was wondering if anybody can guide me for the proper way to allocate memory for the dynamic arrays , probably in the constructor/deconstructor, and also if I need to explicitly call them to make sure I don't get a seg fault.
Here is a simplified version of the related part of my code:
class Network {
public:
int n_nodes;
int user_index[MAX_USERS]; //a fixed array
int adjacency_matrix[][MAX_ITEMS];
//Network(int n_node, int** adjacency); //I would rather to set the element s in a function other than the constructor
Initializer(int n_node, int** adjacency);
~Netowrk();
}
So here are my specific question for this class:
1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
2 - where should I delete the 2D array? should I write it in the deconstructor? Should I call the deconstructor explicitly? Is there anything else I need to destroy in the deconstructor?
1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
Yes. The best way to do this, however, is not to use arrays at all. Instead, use std::vector, which manages the memory for you. There are two ways that you can do this. If you actually want to be able to use the [row][column] syntax to access elements, you'll need to use two dimensions of std::vectors:
std::vector<std::vector<int> > adjacency_matrix;
Once you know the dimensions, you can populate it:
adjacency_matrix.assign(rows, std::vector<int>(columns));
It is often easier to use a single-dimensional array (or a std::vector<int>) containing all of the elements and use row * row_count + column to access the element at index (row, column). This way, there are fewer dynamic allocations. You can wrap up the logic of accessing elements into a couple of helper functions.
2 - where should I delete the 2D array? should I write it in the deconstructor?
You don't have to delete anything if you use a std::vector. It cleans itself up.
Should I call the [destructor] explicitly?
No.
Is there anything else I need to destroy in the [destructor]?
Ideally, no. If you use the Standard Library containers, like std::vector and smart pointers, you shouldn't have to clean anything up. You should avoid trying to manage resources on your own in C++: there are library facilities to do this tedious task for you and you should take advantage of them.
1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
Yes you can. For example:
int* adjacency_matrix_;
int* getAdjacency(int i, int j)
{
if (!adjacency_matrix_)
return 0;
else
return adjacency_matrix_ + i*n_nodes + j;
}
Network()
: n_nodes(0),
adjacency_matrix_(0)
{}
void Initializer(int n_node, int** adjacency)
{
adjacency_matrix_ = new int[n_nodes * n_nodes];
// Copy over data.
}
As to whether you should, that depends on whether you have a reason for not using std::vector<>.
2 - where should I delete the 2D array? should I write it in the deconstructor?
Should I call the deconstructor explicitly?
Is there anything else I need to destroy in the deconstructor?
Yes, definitely free in the destructor using array operator delete:
~Network()
{
delete [] adjacency_matrix_;
}
No, your destructor will be called whenever the Network object itself goes out of scope. It is (very) rarely necessary to make an explicit destructor call.
No, all a destructor needs to explicitly release is whatever your explicitly acquire.
You may like the example matrix class I wrote in an answer to another question
The question itself was about good C++ design practices, but the chosen example was a multi-dimensional array.
There are several ways to do this.
The easiest way is to use vectors, and if you don't like to manage your own memory, this is perfect for you. However, because I like to manage my own memory, and I have found this method to be slow and cumbersome at times, I have learned of other ways.
The fastest way is to allocated a one dimensional array and treat it as you would a two dimensional array. Here is an example:
int *array = new int[width*height];
int get_array(int column, int row)
{
return array[row*width + column];
}
delete [] array;
This can be generalized to the nth-dimension:
int *array = new int[w1*w2*...*wn];
int get_array(int i1, int i2, ..., int in)
{
return array[in*(w1*w2*...*w(n-1)) + i(n-1)*(w1*w2*...*w(n-2)) + ... + i2*w1 + i1];
}
delete [] array;
If you want to be able to have different widths for each row, then you can make an array of pointers. This solution is slow to initialize and clean up, but flexible, tunable, and has relatively fast execution time. It can also be extremely dangerous if you make a mistake though.
int **array = new int*[height];
for (int i = 0; i < height; i++)
array[i] = new int[width(i)];
at which point, to access it, all you have to do is the customary
array[i][j]
however, to free this array you have to do it row by row
for (int i = 0; i < height; i++)
delete [] array[i];
delete [] array;
This can also generalize to the nth dimension.
int **....*array = new int**...*[w1];
for (int i1 = 0; i1 < w1; i1++)
{
array[i1] = new int**..*[w2];
for (int i2 = 0; i2 < w2; i2++)
{
array[i1][i2] = new int**.*[w3];
...
for (int in = 0; in < wn; in++)
array[i1][i2]...[in] = new int[wn];
}
}
for (int i1 = 0; i1 < w1; i1++)
{
for (int i2 = 0; i2 < w2; i2++)
{
...
for (int in = 0; in < wn; in++)
delete [] array[i1][i2]...[in];
...
delete [] array[i1][i2];
}
delete [] array[i1];
}
delete [] array;
This kind of setup tends to wreak havoc on memory. Just a two dimensional array of these would result in width+1 separate arrays to be malloc-ed. It would be faster to just malloc one big array and figure out the indices yourself.