C++ pointer comparison with []operator for arrays? - c++

I have been reading a book which says that accessing array elements by pointer arithmetic's is much faster than the [] operator. In short this code is faster than this code.
The book does not say why. Is it advisible to use such pointer arithmetic's even if it provides significant improvement in speed?
#include <iostream>
using namespace std;
int main() {
// your code goes here
double *array = new double[1000000];
for(int i = 0; i < 1000000; i++)
{
array[i] = 0;//slower?
}
delete[] array;
return 0;
}
#include <iostream>
using namespace std;
int main() {
// your code goes here
double *array = new double[1000000];
for(int i = 0; i < 1000000; i++)
{
*(array + i) = 0;//faster?
}
delete[] array;
return 0;
}
EDIT:
Quote from book pg 369, 2nd last line
The pointer accessing method is much faster than array indexing.

No, they are exactly the same thing. I definitely suggest you to drop that book and pick another one up as soon as possible.
And even if there was any performance difference, the clarity of x[12] over *(x + 12) is much more important.

Array indices are just syntactic sugar for pointer arithmetic. Your compiler will boil down a[i] into *((a) + (i)). Agreed, run away from that book!
For more in-depth explanations, see
SO Answer
Eli Bendersky's explanation

There is no difference at all, if we go to the draft C++ standard section 5.2.1 Subscripting paragraph 1 says (emphasis mine):
[...]The expression E1[E2] is identical (by definition) to *((E1)+(E2)) [Note: see 5.3 and 5.7 for details of * and + and 8.3.4 for details of arrays. —end note ]

Utter rubbish. a[x] on a plain array decays into *(a + x). There will literally be 0 performance difference.

The book is just plain wrong - especially if those are the actual examples they gave. Decent compilers are likely to produce identical code for both methods, even without optimization and they will have identical performance.
Without optimization, or with compilers from the 80s, you might get performance differences with some types of pointer arithmetic, but the examples don't even represent that case. The examples are basically just different syntax for the same thing.
Here's an example that could plausibly have a performance difference (versus the array index case which is unchanged):
int main() {
// your code goes here
double *array = new double[1000000], *ptr = array;
for(; ptr < array + 1000000; ptr++)
{
*ptr = 0;
}
return 0;
}
Here, you aren't indexing against the base pointer each time through the loop, but are incrementing the pointer each time. In theory, you avoid the multiplication implicit in indexing, resulting in a faster loop. In practice, any decent compiler can reduce the indexed form to the additive form, and on modern hardware the multiplication by sizeof(double) implied by indexing is often free as part of an instruction like lea (load effective address), so even at the assembly level the indexed version may not be slower (and may in fact be faster since it avoids a loop-carried dependency and also lends itself better to aliasing analysis).

Your two forms are the same, you're not really doing pointer arithmetic.
The pointer form would be:
double * array= new double[10000000] ;
double * dp= array ;
for ( int i= 0 ; ( i < 10000000 ) ; i ++, dp ++ )
{
* dp= 0 ;
}
Hear, the address in dp is moved to the next one via an add. In the other forms, the address is calculated each go through the loop by multiplying i time sizeof(double) and adding it to array. Its the multiply that historically was slower than the add.

Related

Using a size_t as limiter for a "for loop"

I'm using a C++ app on my s6 named CppDroid to make a quick program.
How do you use a size_t as limiter for a "for loop" on it's counter?
int c;
//... more codes here...
for (c=0; c < a.used; ++c)
//... more codes here...
The a.used is a number of used array that came from a solution to make a dynamic sized array
The error is: comparison of integer of different signs: 'int' and 'size_t' (aka unsigned int)
The for loop is one of an internal nested loops of the program so I want to maintain variable c as an "int" as much as possible.
I've seen examples about Comparing int with size_t but I'm not sure how it can help since it is for an "if" condition.
Just use std::size_t c instead of int c.
As long as a.used doesn't change during the iteration, a common idiom is:
for(int c=0, n=a.used; c<n; ++c) {
...
}
In this way, the cast happens implicitly, and you also have the "total number of elements" variable n handy in the loop body. Also, when n comes from a methods call (say, vec.size()) you evaluate it just once, which is slightly more efficient.1
1. In theory the compiler may do this optimization by itself, but with "complicated" stuff like std::vector and a nontrivial loop body it's surprisingly difficult to prove that it's a loop invariant, so often it's just recalculated at each iteration.
Regarding
” comparison of integer of different signs: 'int' and 'size_t' (aka unsigned int)
… this is a warning. It's not an error that prevents creation of an executable, unless you've asked the compiler to treat warnings as errors.
A very direct way to address it is to use a cast, int(a.size).
More generally I recommend defining a common function to do that, e.g. named n_items (C++17 will have a size function, unfortunately with unsigned result and conflating two or more logical functions, so that name's taken):
using My_array = ...; // Whatever
using Size = ptrdiff_t;
auto n_items( My_array const& a )
-> Size
{ return a.used; }
then for your loop:
for( int c = 0; c < n_items( a ); ++c )
By the way it's generally Not A Good Idea™ to reuse a variable, like c here. I'm assuming that that reuse was unintentional. The example above shows how to declare the loop variable in the for loop head.
Also, as Matteo Italia notes in his answer, it can sometimes be a good idea to manually optimize a loop like this, if measuring shows it to be a bottleneck. That's because the compiler can't easily prove that the result of the n_items call, or any other dynamic array size expression, is the same (is “invariant”) in all executions of the loop body.
Thus, if measuring tells you that the possibly repeated size expression evaluations are a bottleneck, you can do e.g.
for( int c = 0, n = n_items( a ); c < n; ++c )
It's worth noting that any manual optimization carries costs, which are not easy to measure, but which are severe enough that the usual advice to is to defer optimization until measurements tell you that it's really needed.

Different ways to access array's element

As well as I know, there are two ways to access array's element in C++:
int array[5]; //If we have an array of 5 integers
1) Using square brackets
array[i]
2) Using pointers
*(array+i)
My university's teacher forces me to use *(array+i) method, telling me that "it's more optimized".
So, can you please explain, is there any real difference between them? Does the second method has any advantages over the first one?
Is one option more optimized than the other ?
Well, let's see in practice the assembler code generated with MSVC2013 (NON-OPTIMIZED debug mode):
; 21 : array[i] = 8;
mov eax, DWORD PTR _i$[ebp]
mov DWORD PTR _array$[ebp+eax*4], 8
; 22 : *(array + i) = 8;
mov eax, DWORD PTR _i$[ebp]
mov DWORD PTR _array$[ebp+eax*4], 8
Well, with the best will, I cannot see any difference in the code generated.
By the way, someone recently wrote on SO: premature optimizing is the root of all evil. Your teacher should know that !
Has one an advantage over the other ?
Clearly, option one has the advantage of being intuitive and readable. Option2 becomes quickly UNREADABLE in mathematical applications.
Example 1: distance of a 2D mathematical vector implemented as an array.
double v[2] = { 2.0, 1.0 };
// option 1:
double d1 = sqrt(v[0] * v[0] + v[1] * v[1]);
//option 2:
double d2 = sqrt(*v**v + *(v + 1)**(v + 1));
In fact the second option is really misleading due to the **, because you have to read the formula carefully to understand if it's a double dereference or a multiplication by a dereferenced pointer. Not speaking of people who might be mislead by some other languages like ADA in which ** means "power"
Example 2: calculation of the determinant of a 2x2 matrix
double m[2][2] = { { 1.0, 2.0 }, { 3.0, 4.0 } };
// option 1
double dt1 = m[0][0] * m[1][1] - m[1][0] * m[0][1];
// option 2
double *x = reinterpret_cast<double*>(m);
double dt2 = *x **(x+2*1+1) - *(x+2*1) * *(x+1);
With multidimensional arays, option 2 is a nightmare. Note that :
I've used a temporary one dimensional pointer x to be able to use the formula. Using m here would have caused misleading compilation error messages.
you have to know the precise layout of your object and you have to introduce the size of the first dimension in every formula !
Imagine that later on you want to increase the number of elements in your 2D array. You'll have to rewrite everything !
Semantic gap
What your teacher is missing here, is that the operator [] has a meaning that is well understood by the compiler and the reader. It's an abstraction that is not dependent on how your data structure is implemented in reality.
Suppose you have an array and a very simple code:
int w[10] {0};
... // put something in w
int sum = 0;
for (int i = 0; i < 10; i++)
sum += w[i];
Later you decide to use a std::vector instead of an array, because you've learnt that it's much more flexible and powerful. All you have to do is to change the definition (and initialisation) of w :
vector<int> w(10,0);
The rest of your code will work, because the semantic of [] is the same for the two data strutures. I let you imagine what would have hapened if you'd have used your teacher's advice...
"My university's teacher forces me to use *(array+i) method, telling me that "it's more optimized"."
What are they telling you please? If you didn't got something completely wrong with this statement1, ask them for a proof regarding the generated assembler code (#Christophe was giving one in his answer here). I don't believe they could give you such, when looking in deeper.
You could easily check this out yourself using the e.g. the -S option of GCC to produce the assembler code, and compare the results achieved with one or the other version.
Any decent, modern C++ compiler will produce the exactly same assembler code for both of these statements, as long they refer to any c++ fundamental types.
"Does the second method has any advantages over the first one?"
No. The opposite appears to occur, because of less intuitive readability of the code.
1) For class/struct types there could be overloads of the T& operator[](int index) that do things behind the scenes, but if so, *(array+i) should be implemented to behave consistently.
My university's teacher forces me to use *(array+i) method, telling me that "it's more optimized".
Your teacher is absolutely wrong.
The standard defines array[i] to be equivalent to *(array+i), and there is no reason for a compiler to treat them otherwise. They are the same. Neither will be "more optimized" than the other.
The only reason to recommend one over the other is convention and readability and, in those competitions, array[i] wins.
I wonder what else your teacher is getting wrong? :(

How does gcc allocate statically run time known length of array

I wrote the following code:
int tester(int n)
{
int arr[n];
// ...
}
This code compiled, no warnings, using g++.
My question is - how? The parameter n is known just in runtime, in the array is statically allocated. How does gcc compile this?
This is an extension that GCC offers for C++, though variable-length arrays ("VLAs") are properly supported by C since C99.
The implementation isn't terribly hard; on a typical call-stack implementation, the function only needs to save the base of the stack frame and then advance the stack pointer by the dynamically specified amount. VLAs always come with the caveat that if the number is too large, you get undefined behaviour (manifesting in Stack Overflow), which makes them much tricker to use right than, say, std::vector.
There had at some point been an effort to add a similar feature to C++, but this turns out surprisingly difficult in terms of the type system (e.g. what is the type of arr? How does it get deduced in function templates?). The problems are less visible in C which has a much simpler type system and object model (but that said, you can still argue that C is worse off for having VLAs, a considerable part of the standard is spent on them, and the language would have been quite a bit simpler without them, and not necessarily poorer for it).
The GNU C library provides a function to allocate memory on the stack - alloca(3). It simply decrements the stack pointer thus creating some scratch space on it. GCC uses alloca(3) to implement C99 variable-length arrays - it first decrements the stack pointer in the function prologue to create space for all automatic variables, whose size is known at compile time, and then uses alloca(3) to further decrement it and make space for arr with size as determined at run-time. The optimiser might actually fuse both decrements.
int tester(int n)
{
int arr[n];
return 0;
}
compiles into
;; Function tester (tester)
tester (int n)
{
int arr[0:D.1602D.1602] [value-expr: *arr.1];
int[0:D.1602D.1602] * arr.1;
long unsigned int D.1610D.1610;
int n.0;
...
<bb 2>:
n.0 = n;
...
D.1609D.1609 = (long unsigned int) n.0;
D.1610D.1610 = D.1609D.1609 * 4;
D.1612D.1612 = __builtin_alloca (D.1610D.1610); <----- arr is allocated here
arr.1 = (int[0:D.1602D.1602] *) D.1612D.1612;
...
That's equivalent to the following C code:
int tester(int n)
{
int *arr = __builtin_alloca(n * sizeof(int));
return 0;
}
__builtin_alloca() is GCC's internal implementation of alloca(3).

C/C++ intentional out of range indexing [duplicate]

This question already has answers here:
Access array beyond the limit in C and C++ [duplicate]
(7 answers)
How dangerous is it to access an array out of bounds?
(12 answers)
Closed 9 years ago.
Say I have an array like so:
int val[10];
and I intentionally index it with everything from negative values to anything higher than 9, but WITHOUT using the resulting value in any way. This would be for performance reasons (perhaps it's more efficient to check the input index AFTER the array access has been made).
My questions are:
Is it safe to do so, or will I run into some sort of memory protection barriers, risk corrupting memory or similar for certain indices?
Is it perhaps not at all efficient if I access data out of range like this? (assuming the array has no built in range check).
Would it be considered bad practice? (assuming a comment is written to indicate we're aware of using out of range indices).
It is undefined behavior. By definition, undefined means "anything could happen." Your code could crash, it could work perfectly, it could bring about peace and harmony amongst all humans. I wouldn't bet on the second or the last.
It is Undefined Behavior, and you might actually run afoul of the optimizers.
Imagine this simple code example:
int select(int i) {
int values[10] = { .... };
int const result = values[i];
if (i < 0 or i > 9) throw std::out_of_range("out!");
return result;
}
And now look at it from an optimizer point of view:
int values[10] = { ... };: valid indexes are in [0, 9].
values[i]: i is an index, thus i is in [0, 9].
if (i < 0 or i > 9) throw std::out_of_range("out!");: i is in [0, 9], never taken
And thus the function rewritten by the optimizer:
int select(int i) {
int values[10] = { ... };
return values[i];
}
For more amusing stories about forward and backward propagation of assumptions based on the fact that the developer is not doing anything forbidden, see What every C programmer should know about Undefined Behavior: Part 2.
EDIT:
Possible work-around: if you know that you will access from -M to +N you can:
declare the array with appropriate buffer: int values[M + 10 + N]
offset any access: values[M + i]
As verbose said, this yields undefined behavior. A bit more precision follows.
5.2.1/1 says
[...] The expression E1[E2] is identical (by definition) to *((E1)+(E2))
Hence, val[i] is equivalent to *((val)+i)). Since val is an array, the array-to-pointer conversion (4.2/1) occurs before the addition is performed. Therefore, val[i] is equivalent to *(ptr + i) where ptr is an int* set to &val[0].
Then, 5.7/2 explains what ptr + i points to. It also says (emphasis are mine):
[...] If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.
In the case of ptr + i, ptr is the pointer operand and the result is ptr + i. According to the quote above, both should point to an element of the array or to one past the last element. That is, in the OP's case ptr + i is a well defined expression for all i = 0, ..., 10. Finally, *(ptr + i) is well defined for 0 <= i < 10 but not for i = 10.
Edit:
I'm puzzled to whether val[10] (or, equivalently, *(ptr + 10)) yields undefined behavior or not (I'm considering C++ not C). In some circumstances this is true (e.g. int x = val[10]; is undefined behavior) but in others this is not so clear. For instance,
int* p = &val[10];
As we have seen, this is equivalent to int* p = &*(ptr + 10); which could be undefined behavior (because it dereferences a pointer to one past the last element of val) or the same as int* p = ptr + 10; which is well defined.
I found these two references which show how fuzzy this question is:
May I take the address of the one-past-the-end element of an array?
Take the address of a one-past-the-end array element via subscript: legal by the C++ Standard or not?
If you put it in a structure with some padding ints, it should be safe (since the pointer actually points to "known" destinations).
But it's better to avoid it.
struct SafeOutOfBoundsAccess
{
int paddingBefore[6];
int val[10];
int paddingAfter[6];
};
void foo()
{
SafeOutOfBoundsAccess a;
bool maybeTrue1 = a.val[-1] == a.paddingBefore[5];
bool maybeTrue2 = a.val[10] == a.paddingAfter[0];
}

C++ array[index] vs index[array] [duplicate]

This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
In C arrays why is this true? a[5] == 5[a]
Is the possibility of both array[index] and index[array] a compiler feature or a language feature. How is the second one possible?
The compiler will turn
index[array]
into
*(index + array)
With the normal syntax it would turn
array[index]
into
*(array + index)
and thus you see that both expressions evaluate to the same value. This holds for both C and C++.
From the earliest days of C, the expression a[i] was simply the address of a[0] added to i (scaled up by the size of a[0]) and then de-referenced. In fact, all these were equivalent:
a[i]
i[a]
*(a+i)
====
The only thing I'd be concerned about is the actual de-referencing. Whilst they all produce the same address, de-referencing may be a concern if the types of a and i are different.
For example:
int i = 4;
long a[9];
long x = a[i]; //get the long at memory location X.
long x = i[a]; //get the int at memory location X?
I haven't actually tested that behavior but it's something you may want to watch out for. If it does change what gets de-referenced, it's likely to cause all sorts of problems with arrays of objects as well.
====
Update:
You can probably safely ignore the bit above between the ===== lines. I've tested it under Cygwin with a short and a long and it seems okay, so I guess my fears were unfounded, at least for the basic cases. I still have no idea what happens with more complicated ones because it's not something I'm ever likely to want to do.
As Matthew Wilson discusses in Imperfect C++, this can be used to enforce type safety in C++, by preventing use of DIMENSION_OF()-like macros with instances of types that define the subscript operator, as in:
#define DIMENSION_OF_UNSAFE(x) (sizeof(x) / sizeof((x)[0]))
#define DIMENSION_OF_SAFER(x) (sizeof(x) / sizeof(0[(x)]))
int ints[4];
DIMENSION_OF_UNSAFE(ints); // 4
DIMENSION_OF_SAFER(ints); // 4
std::vector v(4);
DIMENSION_OF_UNSAFE(v); // gives impl-defined value; v likely wrong
DIMENSION_OF_SAFER(v); // does not compile
There's more to this, for dealing with pointers, but that requires some additional template smarts. Check out the implementation of STLSOFT_NUM_ELEMENTS() in the STLSoft libraries, and read about it all in chapter 14 of Imperfect C++.
edit: some of the commenters suggest that the implementation does not reject pointers. It does (as well as user-defined types), as illustrated by the following program. You can verify this by uncommented lines 16 and 18. (I just did this on Mac/GCC4, and it rejects both forms).
#include <stlsoft/stlsoft.h>
#include <vector>
#include <stdio.h>
int main()
{
int ar[1];
int* p = ar;
std::vector<int> v(1);
printf("ar: %lu\n", STLSOFT_NUM_ELEMENTS(ar));
// printf("p: %lu\n", STLSOFT_NUM_ELEMENTS(p));
// printf("v: %lu\n", STLSOFT_NUM_ELEMENTS(v));
return 0;
}
In C and C++ (with array being a pointer or array) it is a language feature: pointer arithmetic. The operation a[b] where either a or b is a pointer is converted into pointer arithmetic: *(a + b). With addition being symetrical, reordering does not change meaning.
Now, there are differences for non-pointers. In fact given a type A with overloaded operator[], then a[4] is a valid method call (will call A::operator ) but the opposite will not even compile.