The reason it didn't work is because arrayOfDoubles is a local variable that gets destroyed when the function ends. That means ptrToDouble will point to an object that no longer exists.
to do it the C way (arrays and pointers) you have 2 main ideas.
1) allocate the memory in the function and return it (pointers with new/delete, smart pointers, etc. vector hides the details of this for you). A situationally useful way is a static local in the function, but that depends on what you need. It would always return the same array, every call to the function, which may or may not be useful; it more or less makes the function a global variable surrogate of sorts.
2) pass the memory into the function (where the function only fills in the values, really).
The biggest problem is you are creating a temp array within the scope of the function. The locally created array goes out of scope and is deallocated when the function returns. Your program no longer has 'legal' access to the memory that was used by the local array.
When creating C++ programs it is best to use C++ stdlib containers. Let the container manage the memory for you. A std::vector would be a good choice. Another would be std::array.
With that said:
Allocating the memory manually for the array on the heap/free store is one possible solution, a very 'C++ that looks like C' solution:
#include <iostream>
double* f();
int main()
{
double* ptrToDouble { f() };
std::cout << ptrToDouble[ 0 ] << '\t';
std::cout << ptrToDouble[ 1 ] << '\n';
// it pays to be neat. this delete isn't necessary
// the memory will be deallocated when the program terminates
// ultimate question is 'who owns this memory?'
// f() or main()?
delete[] ptrToDouble;
}
double* f()
{
// create the array on the heap/free store to survive
// deallocation of local assets when the function returns
double* arrayOfDoubles = newdouble[ 2 ];
arrayOfDoubles[ 0 ] = 1.2;
arrayOfDoubles[ 1 ] = 2.3;
std::cout << arrayOfDoubles[ 0 ] << '\t';
std::cout << arrayOfDoubles[ 1 ] << '\n';
return arrayOfDoubles;
}
Passing objects created using new leads to the "who owns the memory" dilemma. Is it the f() function or main()? Deleting manually allocated memory can present problems when changing scope. Problems that can be nigh um-possible to track down.
I prefer to leverage what C++ has to offer and not deal with manual memory management if I don't have to.
Another solution is to create the array in main and pass it to f():
No manual memory management, but when passing regular arrays into a function they decay to a pointer so passing the size of the array is highly recommended.
The degradation of regular arrays to a pointer is yet another reason to prefer using C++ containers, they retain their awareness of their size when passed.
#include <iostream>
double* f();
int main()
{
double* ptrToDouble { f() };
std::cout << ptrToDouble[ 0 ] << '\t';
std::cout << ptrToDouble[ 1 ] << '\n';
// it pays to be neat. this delete isn't necessary
// the memory will be deallocated when the program terminates
// ultimate question is 'who owns this memory?'
// f() or main()?
delete[] ptrToDouble;
}
double* f()
{
// create the array on the heap/free store to survive
// deallocation of local assets when the function returns
double* arrayOfDoubles = newdouble[ 2 ] { 1.2, 2.3 };
std::cout << arrayOfDoubles[ 0 ] << '\t';
std::cout << arrayOfDoubles[ 1 ] << '\n';
return arrayOfDoubles;
}
You should mention that declaring the array as static makes there be one, single array for the lifetime of the program, which might not be what OP wanted.
Where expression templates or (proxy objects in general) are involved, the rule could be:
'Almost Never Auto' or 'Quite Rarely Auto'
Common pitfalls (Eigen):
In short: do not use the auto keywords with Eigen's expressions, unless you are 100% sure about what you are doing. In particular, do not use the auto keyword as a replacement for a Matrix<> type. https://eigen.tuxfamily.org/dox/TopicPitfalls.html
In particular, be wary about unbridled use of deduced return types for functions.
There's always the exception that proves the rule...
1 2 3 4 5 6 7 8 9 10 11 12 13
#include <valarray>
#include <iostream>
auto almost_always_auto()
{
std::valarray<int> va { 0, 1, 2, 3, 4, 5 } ;
return va *= 5;
}
int main()
{
for ( auto e : almost_always_auto() ) std::cout << e << ' ';
}
AAA is one of those things I was calling eggheadery. The reasons given for it are just arm waving to support a preference by the folks that came up with it and followers. It makes code that much more difficult to follow if you use it on everything. Coming from having had to deal with a lot of old school matlab code, where anything can be any type at any time, that was a nightmare when a novice gave you a piece of code. Now its a string, now its a matrix, now its a double, now its a matrix again... auto isn't quite that bad, but I am very against using it everywhere. If modern IDE did not have mouseover - type showing, I would be against using it most places, but with that, I can tolerate reasonable use of it esp ugly iterators or templates. To me overuse of auto is like putting in 200 typedefs and macros to make your c++ look more like pascal.
I think auto has a cost in terms of readability but sometimes it's worth it.
Personally I often use it with iterators, less often with range-based for loops (I did for a while but found that my code became much harder to understand).
for (auto it = sprites.begin(); it != sprites.end(); ++it)
for (Sprite* sprite : sprites)
I might also use it when storing the result of make_unique because I think all the information is easily available on the right hand side.
auto sprite = std::make_unique<Sprite>();
Obviously I also use it with lamdas if I need to store them in a variable (there is no other choice).
auto lambda = [](){};
Otherwise I think auto is mostly useful in templated code.
This is just my personal opinion. I'm not hating. People can use AAA if they want. My only worry is that influential people like Herb Sutter will influence the design of C++ to make it cumbersome to write new things in other ways, or that it becomes an accepted fact that writing it this way is the "only right way". I think there is already a tendency towards making changes to benefit "generic programming" that are not necessarily the best for "normal" (non-templated) code which I think is after all the most common type of code (is it not?). It might be hard to realize for people working on the standard library and other heavily templated libraries.