Accessing a std::array via a unique_ptr - c++

This is just for learning purposes, I know I can just use a vector but I have
const int N = 1e3;
auto my_arr = std::make_unique<std::array<int, N>>();
// To access it I have to do this - why [0][0] twice?
my_arr.get()[0][0] = 1;
// Getting the size for fun
std::cout << sizeof(my_arr.get()) << "\n"; // outputs 8
std::cout << sizeof(my_arr.get()[0]) << "\n"; // outputs 800000000
std::cout << sizeof(my_arr.get()[0][0]) << "\n"; // outputs 8
I understand that .get() returns a pointer to the managed object but I don't understand why I need to do my_arr.get()[0][0] twice?

my_arr.get() gives you a std::array<int, N>*. Since you have a pointer doing pointer[0] is the same as *pointer. So you don't actually need my_arr.get()[0][0] and you can instead use
(*my_arr.get())[0]
to show that you are dereferencing the pointer. In fact, you could just use
(*my_arr)[0]
because operator * is overloaded for std::unique_ptr and it will return a reference to the pointed to thing.

Well, you don't have to do that, but it works.
my_arr.get() returns a std::array<int,N>*
Like any pointer, you can index it like an array.
my_arr.get()[0] returns a reference to the first element in your 'array' of arrays.
You can then use std::array's indexing operator to get an element.
my_arr.get()[0][0] returns a reference to the element you want.
Alternatively, you could write:
my_arr->at(0)
my_arr->operator[](0)
(*my_arr)[0]
*my_arr->data()

You probably don't want to do this:
auto my_arr = std::make_unique<std::array<int, N>>();
Unless you really specifically want an array<int, N>. If what you just want to do is dynamically allocate N ints and manage that with a unique_ptr, that's:
auto my_arr = std::make_unique<int[]>(N);
The advantages here are:
N can be a runtime value, it doesn't have to be a constant-expression.
unique_ptr<T[]>::operator[] exists and does what you want, so my_arr[2] does index into the array.

As you said yourself .get() returns a pointer to the managed object.
So it is std::array<int, N>* what you return and not std::array<int, N>:
std::array<int, N>* array_ptr = my_arr.get();
So either write (*my_arr)[0] or (*my_arr.get())[0]

Related

Passing std::vector::data to function expecting type** (double pointer)

As the title describes, I am trying to pass the pointer to the data of a std::vector into a function expecting a double pointer. Take as an example the code below. I have an int pointer d which is passed to myfunc1 as &d (still not sure if call it the pointer's reference or what), where the function changes its reference to the beginning of an int array filled with 1,2,3,4. However, if I have a std::vector of ints and try to pass &(vec.data()) to myfunc1 the compiler throws the error lvalue required as unary ‘&’ operand. I have already tried something like (int *)&(vec.data()) as per this answer, but it does not work.
Just for reference, I know I can do something like myfunc2 where I directly pass the vector as reference and the job is done. But I want to know if it's possible to use myfunc1 with the std::vector's pointer.
Any help will be very much appreciated.
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
void myfunc1(int** ptr)
{
int* values = new int[4];
// Fill all the with data
for(auto& i:{0,1,2,3})
{
values[i] = i+1;
}
*ptr = values;
}
void myfunc2(vector<int> &vec)
{
int* values = new int[4];
// Fill all the with data
for(auto& i:{0,1,2,3})
{
values[i] = i+1;
}
vec.assign(values,values+4);
delete values;
}
int main()
{
// Create int pointer
int* d;
// This works. Reference of d pointing to the array
myfunc1(&d);
// Print values
for(auto& i:{0,1,2,3})
{
cout << d[i] << " ";
}
cout << endl;
// Creates the vector
vector<int> vec;
// This works. Data pointer of std::vector pointing to the array
myfunc2(vec);
// Print values
for (const auto &element : vec) cout << element << " ";
cout << endl;
// This does not work
vector<int> vec2;
vec2.resize(4);
myfunc1(&(vec2.data()));
// Print values
for (const auto &element : vec2) cout << element << " ";
cout << endl;
return 0;
}
EDIT: What my actual code does is to read some binary files from disk, and load parts of the buffer into the vector. I was having troubles getting the modified vector out of a read function, and this is what I came up with that allowed me to solve it.
When you write:
myfunc1(&(vec2.data()));
You are getting the address of a rvalue. The pointed int* is so a temporary that is destroyed right after the call.
This is why you get this error.
But, as #molbdnilo said, in your myfunc1() function, you are reassigning the pointer (without caring to destroy previously allocated memory by the way).
But the std::vector already manages its data memory on its own. You cannot and you must not put your hands on it.
What my actual code does is to read some binary files from disk, and load parts of the buffer into the vector.
A solution could be to construct your std::vector by passing the iterator to the beginning and the iterator to the end of the desired part to extract in the constructor's parameters.
For example:
int * buffer = readAll("path/to/my/file"); // Let's assume the readAll() function exists for this example
// If you want to extract from element 5 to element 9 of the buffer
std::vector<int> vec(buffer+5, buffer+9);
If the std::vector already exists, you can use the assign() member function as you already did in myfunc2():
vec.assign(buffer+5, buffer+9);
Of course in both cases, you have to ensure that you are not trying to access an out of bounds element when accessing the buffer.
The problem is that you cannot take the address of data(), since it is only a temporary copy of the pointer, so writing to a pointer to it makes not that much sense. And that is good that way. You DO NOT want to pass data() to this function since it would overwrite the pointer with a new array and that would break the vector. You can remove one * from the function and only assign to it and not allocate the memory there. This will work, but make sure to allocate the memory in the caller (with resize, just reserve will result un undefined behavior, since data() is only a pointer to the beginning of the valid range [data(), data() + size()). The range [data(), data() + capacity ()) is not necessary valid.

Can we use conventional pointer arithmetic with std::array?

I want to work out how to use old style pointer arithmetic on pointers to elements of the std::array class. The following code (unsurprisingly perhaps) does not compile:
int main(int argc, char *argv[])
{
double* data1 = new double[(int)std::pow(2,20)];
std::cout << *data1 << " " << *(data1 +1) << std::endl;
delete data1;
data1 = NULL;
double* data2 = new std::array<double, (int)std::pow(2,20)>;
std::cout << *data2 << " " << *(data2 +1) << std::endl;
delete data2;
data2 = NULL;
return 0;
}
As an exercise, I want to use all the conventional pointer arithmetic, but instead of pointing at an old style double array, I want it to point to the elements of a std::array. My thinking with this line:
double* data2 = new std::array<double, (int)std::pow(2,20)>;
is to instruct the compiler that data2 is a pointer to the first element of the heap allocated std::array<double,(int)std::pow(2,20)>.
I have been taught that the double* name = new double[size]; means EXACTLY the following: «Stack allocate memory for a pointer to ONE double and name the pointer name, then heap allocate an array of doubles of size size, then set the pointer to point to the first element of the array.» Since the above code does not compile, I must have been taught something incorrect since the same syntax doesnt work for std::arrays.
This raises a couple of questions:
What is the actual meaning of the statement type* name = new othertype[size];?
How can I achieve what I want using std::array?
Finally, how can I achieve the same using std::unqiue_ptr and std::make_unique?
I have been taught that the double* name = new double[size]; means EXACTLY the following: «Stack allocate memory for a pointer to ONE double and name the pointer name, then heap allocate an array of doubles of size size, then set the pointer to point to the first element of the array.» Since the above code does not compile, I must have been taught something incorrect since the same syntax doesnt work for std::arrays.
You are correct about that statement, but keep in mind that the way this works is that new[] is a different operator from new. When you dynamically allocate an std::array, you're calling the single-object new, and the returned pointer points to the std::array object itself.
You can do pointer arithmetic on the contents of an std::array. For example, data2.data() + 1 is a pointer to data2[1]. Note that you have to call .data() to get a pointer to the underlying array.
Anyway, don't dynamically allocate std::array objects. Avoid dynamic allocation if possible, but if you need it, then use std::vector.
Can we use conventional pointer arithmetic with std::array?
Yes, sure you can - but not on the array itself, which is an object. Rather, you use the address of the data within the array, which you get with the std::array's data() method, like so:
std::array<double, 2> data2 { 12.3, 45.6 };
double* raw_data2 = data2.data(); // or &(*data2.begin());
std::cout << *raw_data2 << " " << *(raw_data2 + 1) << std::endl;
and this compiles and runs fine. But you probably don't really need to use pointer arithmetic and could just write your code different, utilizing the nicer abstraction of an std::array.
PS - Avoid using explicit memory allocation with new and delete(see the C++ Core Guidelines item about this issue). In your case you don't need heap allocation at all - just like you don't need it with the regular array.
You can have access to the "raw pointer" view of std::array using the data() member function. However, the point of std::array is that you don't have to do this:
int main(int argc, char *argv[])
{
std::array<double, 2> myArray;
double* data = myArray.data();
// Note that the builtin a[b] operator is exactly the same as
// doing *(a+b).
// But you can just use the overloaded operator[] of std::array.
// All of these thus print the same thing:
std::cout << *(data) << " " << *(data+1) << std::endl;
std::cout << data[0] << " " << data[1] << std::endl;
std::cout << myArray[0] << " " << myArray[1] << std::endl;
return 0;
}
The meaning of a generalized:
type* name = new othertype[size];
Ends up being "I need a variable name that's a pointer to type and initialize that with a contiguous allocation of size instances of othertype using new[]". Note that this involves casting and might not even work as othertype and type might not support that operation. A std::array of double is not equivalent to a pointer to double. It's a pointer to a std::array, period, but if you want to pretend that's a double and you don't mind if your program crashes due to undefined behaviour you can proceed. Your compiler should warn you here, and if it doesn't your warnings aren't strict enough.
Standard Library containers are all about iterators, not pointers, and especially not pointer arithmetic. Iterators are far more flexible and capable than pointers, they can handle exotic data structures like linked lists, trees and more without imposing a lot of overhead on the caller.
Some containers like std::vector and std::array support "random access iterators" which are a form of direct pointer-like access to their contents: a[1] and so on. Read the documentation of any given container carefully as some permit this, and many don't.
Remember that "variable" and "allocated on stack" are not necessarily the same thing. An optimizing compiler can and will put that pointer wherever it wants, including registers instead of memory, or nowhere at all if it thinks it can get away with it without breaking the expressed behaviour of your code.
If you want std::array, which you really do as Standard Library containers are almost always better than C-style arrays:
std::array<double, 2> data2;
If you need to share this structure you'll need to consider if the expense of using std::unique_ptr is worth it. The memory footprint of this thing will be tiny and copying it will be trivial, so it's pointless to engage a relatively expensive memory management function.
If you're passing around a larger structure, consider using a reference instead and locate the structure in the most central data structure you have so it doesn't need to be copied by design.
Sure, these are all legal:
template<class T, std::size_t N>
T* alloc_array_as_ptr() {
auto* arr = new std::array<T,N>;
if (!arr) return nullptr;
return arr->data();
}
template<class T, std::size_t N>
T* placement_array_as_ptr( void* ptr ) {
auto* arr = ::new(ptr) std::array<T,N>;
return arr->data();
}
template<std::size_t N, class T>
std::array<T, N>* ptr_as_array( T* in ) {
if (!in) return nullptr;
return reinterpret_cast<std::array<T,N>*>(in); // legal if created with either above 2 functions!
}
// does not delete!
template<std::size_t N, class T>
void destroy_array_as_ptr( T* t ) {
if (!t) return;
ptr_as_array<N>(t)->~std::array<T,N>();
}
// deletes
template<std::size_t N, class T>
void delete_array_as_ptr(T* t) {
delete ptr_as_array<N>(t);
}
the above is, shockingly, actually legal if used perfectly. The pointer-to-first-element-of-array is pointer interconvertable with the entire std::array.
You do have to keep track of the array size yourself.
I wouldn't advise doing this.
std::array is a STL container after all!
auto storage = std::array<double, 1 << 20>{};
auto data = storage.begin();
std::cout << *data << " " << *(data + 1) << std::endl;

How to index into C++ shared_ptr/unique_ptr array?

As inspired by Demo of shared ptr array
I got the first two lines to work:
std::shared_ptr<string> sp( new string[3], []( string *p ) { delete[] p; } );
*sp = "john";
auto p = &(* sp);
++p = new string("Paul");
++p = new string("Mary");
for(auto q = &(*sp); q <= p; q++) cout << *q << endl;
(1) Can someone show me how to access subsequent elements of my array and print them out with a for loop?
My for loop does not print anything with MSVC V19 and and g++ v4.9 prints "john" but not "Paul" and "Mary" and then gives me a segmentation fault.
Now after some more google/bing searching I found some discussions suggesting I should use unique_ptr if I are not sharing it.
So I got to experimenting some more and this works:
const int len=3;
std::unique_ptr<string[]> up( new string[len] ); // this will correctly call delete[]
up[0] = "john";
up[1] = "paul";
up[2] = "mary";
for(int ii = 0; ii < len; ++ii) cout << up[ii] << endl;
(2) Is there a way to print the array up without hard coding the length in a constant? I was hoping that there was a way to make the new C++ for loop syntax work but it appears only work on std::array and std::vector.
(3) Is there is an easier way to initialize this array? Perhaps with an initializer list?
To access subsequent elements use the shared_ptr::get member function
std::shared_ptr<string> sp( new string[3], std::default_delete<string[]>() );
sp.get()[0] = "John";
sp.get()[1] = "Paul";
sp.get()[2] = "Mary";
for(auto q = sp.get(); q < sp.get() + 3; q++) cout << *q << endl;
The problem with dereferencing the shared_ptr is that it'll return a string&, but you want to get access to the underlying pointer in order to be able to index to next element.
You can also initialize the shared_ptr array upon construction using list initialization
std::shared_ptr<string> sp( new string[3]{"John", "Paul", "Mary"},
std::default_delete<string[]>() );
As for unique_ptr, as you've noted, there exists a partial specialization that'll delete array types correctly. However, it does not store the length of the array, you'll need to store it separately and pass it around along with the unique_ptr. For one-line initialization you can use the same syntax as above.
std::unique_ptr<string[]> up( new string[len]{"John", "Paul", "Mary"} );
However, neither the shared_ptr nor the unique_ptr can be used with ranged-based for loops. The specification of a range for requires the operand to either be an array, or it must have begin() and end() member functions, or the begin and end iterators for the range must be obtainable by ADL using the expressions begin(__range) and end(__range) respectively. None of these conditions are satisfied by either the shared_ptr or the unique_ptr containing an array.
Unless you have a good reason not to, you should just use std::vector<std::string>, that'll save you the trouble of tracking array length separately. std::array<std::string, N>> is also another option if you know the length of the array at compile time.
With C++17, operator[] is defined for shared_ptr<T[]> (link). Before that it was there for unique_ptr, but not for shared_ptr.
So, the following code will work.
std::shared_ptr<string[]> sp(new string[3]);
sp[0] = "John";
sp[1] = "Paul";
sp[2] = "Mary";
for(int i =0; i< 3; i++)
{
cout<<sp[i]<<"\n";
}
Note that it is define for shared_ptr<T[]>, and not for shared_ptr<T>, i.e. when you have a dynamically allocated array. Also I have removed your custom deleter, as your's is similar to the default one which the compiler will use, you are however free to add it.
For your second query - being able to use new C++ for loop (range based for loop), you cannot use this smart pointer directly, since range based for loop works only on containers which have begin(), end(), operator++, operator*() , and, operator!= defined (link).
The simplest way is to use std::vector with pre-allocated size. eg. vector<T> sp(3), or vector<T> sp; sp.reserve(3). This will work as good as your smart pointers' approach. To get underlying memory you can use vector<T>::data() eg. sp.data(). This will give you a dynamic C array of 3 elements (n elements in general).
How to index into C++ shared_ptr/unique_ptr array?
You've already shown the code for unique_ptr.
This works for shared_ptr.
std::shared_ptr<string> sp( new string[3], []( string *p ) { delete[] p; } );
sp.get()[0] = "string 1";
sp.get()[1] = "string 2";
sp.get()[2] = "string 3";

Apply std::begin() on an dynamically allocated array in a unique_ptr?

I have an unique pointer on a dynamically allocated array like this:
const int quantity = 6;
unique_ptr<int[]> numbers(new int[quantity]);
This should be correct so far (I think, the [] in the template parameter is important, right?).
By the way: Is it possible to initialize the elements like in int some_array[quantity] = {}; here?
Now I was trying to iterate over the array like this:
for (auto it = begin(numbers); it != end(numbers); ++it)
cout << *it << endl;
But I cannot figure out, how the syntax is right. Is there a way?
Alternatively I can use the index like:
for (int i = 0; i < quantity; ++i)
cout << numbers[i] << endl;
Is one of these to be preferred?
(Not directly related to the title: As a next step I would like to reduce that to a range-based for loop but I just have VS2010 right now and cannot try that. But would there be something I have to take care of?)
Thank you! Gerrit
Compiler is supposed to apply this prototype for std::begin:
template< class T, size_t N >
T* begin( T (&array)[N] );
It means the parameter type is int(&)[N], neither std::unique_ptr nor int *. If this is possible, how could std::end to calculate the last one?
But why not use raw pointer directly or a STL container?
const int quantity = 6;
std::unique_ptr<int[]> numbers{new int[quantity]};
// assignment
std::copy_n(numbers.get(), quantity,
std::ostream_iterator<int>(std::cout, "\n"));
const int quantity = 6;
std::vector<int> numbers(quantity, 0);
// assignment
std::copy(cbegin(numbers), cend(numbers),
std::ostream_iterator<int>(std::cout, "\n"));
Dynamically allocated arrays in C++ (ie: the result of new []) do not have sizing information. Therefore, you can't get the size of the array.
You could implement std::begin like this:
namespace std
{
template<typename T> T* begin(const std::unique_ptr<T[]> ptr) {return ptr.get();}
}
But there's no way to implement end.
Have you considered using std::vector? With move support, it shouldn't be any more expensive than a unique_ptr to an array.

How does the range-based for work for plain arrays?

In C++11 you can use a range-based for, which acts as the foreach of other languages. It works even with plain C arrays:
int numbers[] = { 1, 2, 3, 4, 5 };
for (int& n : numbers) {
n *= 2;
}
How does it know when to stop? Does it only work with static arrays that have been declared in the same scope the for is used in? How would you use this for with dynamic arrays?
It works for any expression whose type is an array. For example:
int (*arraypointer)[4] = new int[1][4]{{1, 2, 3, 4}};
for(int &n : *arraypointer)
n *= 2;
delete [] arraypointer;
For a more detailed explanation, if the type of the expression passed to the right of : is an array type, then the loop iterates from ptr to ptr + size (ptr pointing to the first element of the array, size being the element count of the array).
This is in contrast to user defined types, which work by looking up begin and end as members if you pass a class object or (if there is no members called that way) non-member functions. Those functions will yield the begin and end iterators (pointing to directly after the last element and the begin of the sequence respectively).
This question clears up why that difference exists.
I think that the most important part of this question is, how C++ knows what the size of an array is (at least I wanted to know it when I found this question).
C++ knows the size of an array, because it's a part of the array's definition - it's the type of the variable. A compiler has to know the type.
Since C++11 std::extent can be used to obtain the size of an array:
int size1{ std::extent< char[5] >::value };
std::cout << "Array size: " << size1 << std::endl;
Of course, this doesn't make much sense, because you have to explicitly provide the size in the first line, which you then obtain in the second line. But you can also use decltype and then it gets more interesting:
char v[] { 'A', 'B', 'C', 'D' };
int size2{ std::extent< decltype(v) >::value };
std::cout << "Array size: " << size2 << std::endl;
According to the latest C++ Working Draft (n3376) the ranged for statement is equivalent to the following:
{
auto && __range = range-init;
for (auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin) {
for-range-declaration = *__begin;
statement
}
}
So it knows how to stop the same way a regular for loop using iterators does.
I think you may be looking for something like the following to provide a way to use the above syntax with arrays which consist of only a pointer and size (dynamic arrays):
template <typename T>
class Range
{
public:
Range(T* collection, size_t size) :
mCollection(collection), mSize(size)
{
}
T* begin() { return &mCollection[0]; }
T* end () { return &mCollection[mSize]; }
private:
T* mCollection;
size_t mSize;
};
This class template can then be used to create a range, over which you can iterate using the new ranged for syntax. I am using this to run through all animation objects in a scene which is imported using a library that only returns a pointer to an array and a size as separate values.
for ( auto pAnimation : Range<aiAnimation*>(pScene->mAnimations, pScene->mNumAnimations) )
{
// Do something with each pAnimation instance here
}
This syntax is, in my opinion, much clearer than what you would get using std::for_each or a plain for loop.
It knows when to stop because it knows the bounds of static arrays.
I'm not sure what do you mean by "dynamic arrays", in any case, if not iterating over static arrays, informally, the compiler looks up the names begin and end in the scope of the class of the object you iterate over, or looks up for begin(range) and end(range) using argument-dependent lookup and uses them as iterators.
For more information, in the C++11 standard (or public draft thereof), "6.5.4 The range-based for statement", pg.145
How does the range-based for work for plain arrays?
Is that to read as, "Tell me what a ranged-for does (with arrays)?"
I'll answer assuming that - Take the following example using nested arrays:
int ia[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
for (auto &pl : ia)
Text version:
ia is an array of arrays ("nested array"), containing [3] arrays, with each containing [4] values. The above example loops through ia by it's primary 'range' ([3]), and therefore loops [3] times. Each loop produces one of ia's [3] primary values starting from the first and ending with the last - An array containing [4] values.
First loop: pl equals {1,2,3,4} - An array
Second loop: pl equals {5,6,7,8} - An array
Third loop: pl equals {9,10,11,12} - An array
Before we explain the process, here are some friendly reminders about arrays:
Arrays are interpreted as pointers to their first value - Using an array without any iteration returns the address of the first value
pl must be a reference because we cannot copy arrays
With arrays, when you add a number to the array object itself, it advances forward that many times and 'points' to the equivalent entry - If n is the number in question, then ia[n] is the same as *(ia+n) (We're dereferencing the address that's n entries forward), and ia+n is the same as &ia[n] (We're getting the address of the that entry in the array).
Here's what's going on:
On each loop, pl is set as a reference to ia[n], with n equaling the current loop count starting from 0. So, pl is ia[0] on the first round, on the second it's ia[1], and so on. It retrieves the value via iteration.
The loop goes on so long as ia+n is less than end(ia).
...And that's about it.
It's really just a simplified way to write this:
int ia[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
for (int n = 0; n != 3; ++n)
auto &pl = ia[n];
If your array isn't nested, then this process becomes a bit simpler in that a reference is not needed, because the iterated value isn't an array but rather a 'normal' value:
int ib[3] = {1,2,3};
// short
for (auto pl : ib)
cout << pl;
// long
for (int n = 0; n != 3; ++n)
cout << ib[n];
Some additional information
What if we didn't want to use the auto keyword when creating pl? What would that look like?
In the following example, pl refers to an array of four integers. On each loop pl is given the value ia[n]:
int ia[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
for (int (&pl)[4] : ia)
And... That's how it works, with additional information to brush away any confusion. It's just a 'shorthand' for loop that automatically counts for you, but lacks a way to retrieve the current loop without doing it manually.
Some sample code to demonstrate the difference between arrays on Stack vs arrays on Heap
/**
* Question: Can we use range based for built-in arrays
* Answer: Maybe
* 1) Yes, when array is on the Stack
* 2) No, when array is the Heap
* 3) Yes, When the array is on the Stack,
* but the array elements are on the HEAP
*/
void testStackHeapArrays() {
int Size = 5;
Square StackSquares[Size]; // 5 Square's on Stack
int StackInts[Size]; // 5 int's on Stack
// auto is Square, passed as constant reference
for (const auto &Sq : StackSquares)
cout << "StackSquare has length " << Sq.getLength() << endl;
// auto is int, passed as constant reference
// the int values are whatever is in memory!!!
for (const auto &I : StackInts)
cout << "StackInts value is " << I << endl;
// Better version would be: auto HeapSquares = new Square[Size];
Square *HeapSquares = new Square[Size]; // 5 Square's on Heap
int *HeapInts = new int[Size]; // 5 int's on Heap
// does not compile,
// *HeapSquares is a pointer to the start of a memory location,
// compiler cannot know how many Square's it has
// for (auto &Sq : HeapSquares)
// cout << "HeapSquare has length " << Sq.getLength() << endl;
// does not compile, same reason as above
// for (const auto &I : HeapInts)
// cout << "HeapInts value is " << I << endl;
// Create 3 Square objects on the Heap
// Create an array of size-3 on the Stack with Square pointers
// size of array is known to compiler
Square *HeapSquares2[]{new Square(23), new Square(57), new Square(99)};
// auto is Square*, passed as constant reference
for (const auto &Sq : HeapSquares2)
cout << "HeapSquare2 has length " << Sq->getLength() << endl;
// Create 3 int objects on the Heap
// Create an array of size-3 on the Stack with int pointers
// size of array is known to compiler
int *HeapInts2[]{new int(23), new int(57), new int(99)};
// auto is int*, passed as constant reference
for (const auto &I : HeapInts2)
cout << "HeapInts2 has value " << *I << endl;
delete[] HeapSquares;
delete[] HeapInts;
for (const auto &Sq : HeapSquares2) delete Sq;
for (const auto &I : HeapInts2) delete I;
// cannot delete HeapSquares2 or HeapInts2 since those arrays are on Stack
}