I have been given a header with the following declaration:
//The index of 1 is used to make sure this is an array.
MyObject objs[1];
However, I need to make this array dynamically sized one the program is started. I would think I should just declare it as MyObject *objs;, but I figure if the original programmer declared it this way, there is some reason for it.
Is there anyway I can dynamically resize this? Or should I just change it to a pointer and then malloc() it?
Could I use some the new keyword somehow to do this?
Use an STL vector:
#include <vector>
std::vector<MyObject> objs(size);
A vector is a dynamic array and is a part of the Standard Template Library. It resizes automatically as you push back objects into the array and can be accessed like a normal C array with the [] operator. Also, &objs[0] is guaranteed to point to a contiguous sequence in memory -- unlike a list -- if the container is not empty.
You're correct. If you want to dynamically instantiate its size you need to use a pointer.
(Since you're using C++ why not use the new operator instead of malloc?)
MyObject* objs = new MyObject[size];
Or should I just change it to a
pointer and then malloc() it?
If you do that, how are constructors going to be called for the objects in on the malloc'd memory? I'll give you a hint - they won't be - you need to use a std::vector.
I have only seen an array used as a pointer inside a struct or union. This was ages ago and was used to treat the len and first char of a string as a hash to improve the speed of string comparisons for a scripting language.
The code was similar to this:
union small_string {
struct {
char len;
char buff[1];
};
short hash;
};
Then small_string was initialised using malloc, note the c cast is effectively a reinterpret_cast
small_string str = (small_string) malloc(len + 1);
strcpy(str.buff, val);
And to test for equality
int fast_str_equal(small_string str1, small_string str2)
{
if (str1.hash == str2.hash)
return strcmp(str1.buff, str2.buff) == 0;
return 0;
}
As you can see this is not a very portable or safe style of c++. But offered a great speed improvement for associative arrays indexed by short strings, which are the basis of most scripting languages.
I would probably avoid this style of c++ today.
Is this at the end of a struct somewhere?
One trick I've seen is to declare a struct
struct foo {
/* optional stuff here */
int arr[1];
}
and malloc more memory than sizeof (struct foo) so that arr becomes a variable-sized array.
This was fairly commonly used in C programs back when I was hacking C, since variable-sized arrays were not available, and doing an additional allocation was considered too error-prone.
The right thing to do, in almost all cases, is to change the array to an STL vector.
Using the STL is best if you want a dynamically sizing array, there are several options, one is std::vector. If you aren't bothered about inserting, you can also use std::list.
Its seems - yes, you can do this change.
But check your code on sizeof( objs );
MyObj *arr1 = new MyObj[1];
MyObj arr2[1];
sizeof(arr1) != sizeof(arr2)
Maybe this fact used somewhere in your code.
That comment is incredibly bad. A one-element array is an array even though the comment suggests otherwise.
I've never seen anybody try to enforce "is an array" this way. The array syntax is largely syntactic sugar (a[2] gives the same result as 2[a]: i.e., the third element in a (NOTE this is an interesting and valid syntax but usually a very bad form to use because you're going to confuse programmers for no reason)).
Because the array syntax is largely syntactic sugar, switching to a pointer makes sense as well. But if you're going to do that, then going with new[] makes more sense (because you get your constructors called for free), and going with std::vector makes even more sense (because you don't have to remember to call delete[] every place the array goes out of scope due to return, break, the end of statement, throwing an exception, etc.).
Related
I have this method:
void createSomething(Items &items)
{
int arr[items.count]; // number of items
}
But it's throwing an error:
expression must have a constant value
I found just this solution:
int** arr= new int*[items.count];
so I'm asking is there a better way how do handle this?
You can use a std::vector
void createSomething(Items &items)
{
std::vector<int> arr(items.count); // number of items
}
The reason your first method won't work is that the size of an array must be know at compile time (without using compiler extensions), so you have to use dynamically sized arrays. You can use new to allocate the array yourself
void createSomething(Items &items)
{
int* arr = new int[items.count]; // number of items
// also remember to clean up your memory
delete[] arr;
}
But it is safer and IMHO more helpful to use a std::vector.
Built in arrays & std::array always require a constant integer to determine their size. Of course in case of dynamic arrays (the one created with new keyword) can use a non-constant integer as you have shown.
However std::vector (which of course internally a dynamic array only) uses a is the best solution when it comes to array-type applications. It's not only because it can be given a non-constant integer as size but also it can grown as well as dynamically quite effectively. Plus std::vector has many fancy functions to help you in your job.
In your question you have to simply replace int arr[items.count]; with :-
std::vector<int> arr(items.count); // You need to mention the type
// because std::vector is a class template, hence here 'int' is mentioned
Once you start with std::vector, you would find yourself preferring it in 99% cases over normal arrays because of it's flexibility with arrays. First of all you needn't bother about deleting it. The vector will take care of it. Moreover functions like push_back, insert, emplace_back, emplace, erase, etc help you make effective insertions & deletions to it which means you don't have to write these functions manually.
For more reference refer to this
I have this method:
void createSomething(Items &items)
{
int arr[items.count]; // number of items
}
But it's throwing an error:
expression must have a constant value
I found just this solution:
int** arr= new int*[items.count];
so I'm asking is there a better way how do handle this?
You can use a std::vector
void createSomething(Items &items)
{
std::vector<int> arr(items.count); // number of items
}
The reason your first method won't work is that the size of an array must be know at compile time (without using compiler extensions), so you have to use dynamically sized arrays. You can use new to allocate the array yourself
void createSomething(Items &items)
{
int* arr = new int[items.count]; // number of items
// also remember to clean up your memory
delete[] arr;
}
But it is safer and IMHO more helpful to use a std::vector.
Built in arrays & std::array always require a constant integer to determine their size. Of course in case of dynamic arrays (the one created with new keyword) can use a non-constant integer as you have shown.
However std::vector (which of course internally a dynamic array only) uses a is the best solution when it comes to array-type applications. It's not only because it can be given a non-constant integer as size but also it can grown as well as dynamically quite effectively. Plus std::vector has many fancy functions to help you in your job.
In your question you have to simply replace int arr[items.count]; with :-
std::vector<int> arr(items.count); // You need to mention the type
// because std::vector is a class template, hence here 'int' is mentioned
Once you start with std::vector, you would find yourself preferring it in 99% cases over normal arrays because of it's flexibility with arrays. First of all you needn't bother about deleting it. The vector will take care of it. Moreover functions like push_back, insert, emplace_back, emplace, erase, etc help you make effective insertions & deletions to it which means you don't have to write these functions manually.
For more reference refer to this
It's common wisdom that you can't return a reference to an array. I've read Why doesn't C++ support functions returning arrays? and one of the answers goes into long winded speculation that it's a design decision. Another answer suggests using a vector or struct instead (what??) and also says:
The array you return would degrade to a pointer though, so you would
not be able to work out its size just from its return.
But it's also common wisdom that you can preserve the size of an array by using a reference. The following works for example:
int arr[10];
int (&func())[10]
{
return arr;
}
int main()
{
int (&arr)[10] = func();
for (int i = 0; i < 10; ++i)
std::cout << i << " ";
}
Aside from the usual "you should use a vector or std::array" what's wrong with this approach? I'm unable to see why people care so much about returning an array when this is possible.
You seem dismissive of vector. However make sure you clearly understand that vector really is the C++ equivalent of an array in Java and many other popular languages. Don't be misled by the slightly different declaration syntax. The beast in C++ that uses [] is very different to a Java array.
Moving onto your question: Yes, you can return a C-style array by reference. Your code is correct. But there are very few use cases for it, which is probably why you haven't seen it before.
In modern C++, it is preferred to avoid using C-style arrays because they do not follow value semantics that other objects have. (For example, they cannot be returned by value from a function). They're an ugliness inherited from C that unfortunately it's too late to delete from the standard entirely.
std::array<int, 10> may look ugly to you at first, however it will behave nicely when you try to copy or move or return it.
The code you wrote is perfectly acceptable. There are a number of reasons why it isn't done more often:
The size of the array must be fixed at compile time. Many functions returning an array would like to return a variable number of elements.
The storage can't be local to the function, or if it is it must be static. You never want to return a reference to an object that no longer exists. It may appear to work, which is actually a bad thing - you won't notice your mistake right away. Your test case is quite artificial, you don't often return a reference to a global.
Another answer suggests using a vector or struct instead (what??)
A struct is copyable, so if you embed an array inside a struct you can return it like a normal value type. You can't do that with an array.
I'm unable to see why people care so much about returning an array when this is possible.
Because what you've done is just not very useful, it's just an accessor to a global array. You're not returning a new array, just the same one each time. This fails:
auto arr1 = func();
auto arr2 = func();
arr1[0] = 1;
arr2[0] = 2;
assert( arr1[0] == 1 ); // fails
The people who want to return an array from a function want to return a different array each time the function is called, not just a reference to the same one every time. The same way you can call a function returning int and it's a different value each time and separate calls don't return references to the same piece of state. You haven't solved their problem, you've just done something else.
Depending on a variable, I need to select the SeedPositions32 or SeedPositions16 array for further use. I thought a pointer would allow this but I can't seed to make it work. How do you declare a pointer to a C++11 std::array? I tried the below.
array<int>* ArrayPointer;
//array<typedef T, size_t Size>* ArrayPointer;
array<int,32> SeedPositions32 = {0,127,95,32,64,96,31,63,16,112,79,48,15,111,80,
47,41,72,8,119,23,104,55,87,71,39,24,7,56,88,103,120};
array<int,16> SeedPositions16 = {...}
std::array has a template parameter for size. Two std::array template instantiations with different sizes are different types. So you cannot have a pointer that can point to arrays of different sizes (barring void* trickery, which opens its own can of worms.)
You could use templates for the client code, or use std::vector<int> instead.
For example:
template <std::size_t N>
void do_stuff_with_array(std::array<int, N> the_array)
{
// do stuff with the_array.
}
do_stuff_with_array(SeedPositions32);
do_stuff_with_array(SeedPositions16);
Note that you can also get a pointer to the data:
int* ArrayPtr = SeedPositions32.data();
but here, you have lose the size information. You will have to keep track of it independently.
You can simply access the content of the std::array as a raw C-like array pointer using the std::array::data() member function:
int* arrayPointer = useSeedPositions32 ? SeedPositions32.data() : SeedPositions16.data();
In his answer juanchopanza explained very well why what you want cannot work.
The question is why would you want to do that? There is no way where you could use a (pointer to) std::array<int,32> in place of std::array<int,16>.
The point of std::array<> is to keep track of the number of elements at compile time (and also to avoid memory allocation for small fixed-sized arrays). If you instead want the number of elements to be managed at run time, you should presumably not use std::array<>, but std::vector.
The alternative of obtaining a pointer to the underlying data (using std::array::data() as proposed in other answers) and keeping track of the number of elements by yourself is somewhat dangerous and not really recommendable. The problem is that you must ensure that the pointer is never dangling.
Finally, I cannot find any possible use case. In order to use your pointer, you must declare both an array<int,32> and an array<int,16> object, yet use only one of them.
Why don't you simply only declare a array<int,32> and use only its first 16 elements if not all 32 are needed?
You could do something like this:
int * myArray = use32 ? &SeedPositions32[0] : &SeedPositions16[0];
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is it possible to dynamically create an array of constant size in C++?
This is rather a theoretical question - I wonder why actually operator new[] in C++ returns pointer to first element of array and not actual array (or a pointer to it). This came to me while trying to do something like
typedef int int4[4];
int4* ni4 = new int4;
While I know why this does not work (although it wasn't so clear in the beginning ;)), it really bugs me that code, which in principle is A* ptr= new A; does not compile. Am I the only one that finds that weird?
What I find strange here is that operator new[] is used. The code tries to allocate a single instance of an aggregate, which would be legal if the aggregate was a struct.
But this is the behavior called out by the standard in section [expr.new].
However, there's a very simple workaround:
typedef int int4[4];
int4* ni4 = new int4[1];
...
delete [] ni4;
It could probably be argued for the following
new (int[N]); // type int(*)[N]
new int[N]; // type int*
new T; /* T* */
Only in the middle case, N can be a runtime value. Nevertheless, the spec does not establish such a type difference. Arrays need special handling anyway in almost all cases (as in, you cannot just copy them either). So you should be prepared to handle them specially. For example, you also have to use delete[] instead of delete in your case.
Just to make it clear, if the above would be true, then you would need awkward syntax
int (*p)[N] = new (int[N]);
(*p)[N-1] = 0;
p[0][N-1] = 0; /* or, equivalently */
p[N-1] = 0; /* but not this, error! */
You would first need to dereference the array pointer.
It's legacy from C, which actually had it as legacy from B. The entire handling of native arrays in C++ is abysmal but they can't change it. This is the case for many problems in C++.
I'm not quite sure if I understand your question. In C++, as in C, there is no difference between a pointer to the first element of an array and the array itself.
EDIT: As has been pointed out to me, this is not really correct - please forgive my mistake, I've been spending too much time with Java and C# recently ;-)