operator overloading performance

Hello,

just wanted to ask You guys, what do you think which one will perform better:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

// Matrix with operator overloading to access to its elements
cMatrix1
{
private:
	float elements[16];

public:
	float operator[](int index)
	{
	    return elements[index];
	}
}

// Matrix where you can access directly to its elements
cMatrix2
{
public:
	float elements[16];
}





int main()
{
	cMatrix1 m1;
	cMatrix2 m2;

	for 1000000 times
	{
		m1[0] = 0;		//is this faster ?

		m2.elemets[0] = 0;	//or this is faster ?
	}
}


Is it faster to use operator overloading for operator []
to access elements in a simple Matrix class,
or is it better to directly access to the elements
of the Matrix ?

Only the performance counts :) i know the first one is more elegant :)


Happy coding !
There's absolutely no difference, the compiler will generate the same code in both cases.
Just check the assembly output when in doubt (-S to compile to assembly instead of object files, --save-temps to save the assembly during "normal" compilation).
closed account (1yR4jE8b)
It's very simple, just check the assembly:

First, using direct access:

operator.cpp
1
2
3
4
5
6
7
8
9
10
11
struct matrix
{
  float elements[16];
  float& operator[](int index) { return elements[index]; }
} m1;

int main()
{
  m1.elements[1] = 2;
  return 0;
}


g++ -S operator.cpp

The main function looks like:
1
2
3
4
5
6
7
8
9
10
main:
	pushq	%rbp
	movq	%rsp, %rbp
	subq	$32, %rsp
	call	__main
	movl	$0x40000000, %eax
	movl	%eax, 4+m1(%rip)
	movl	$0, %eax
	leave
	ret


Now with operator overloading:
1
2
3
4
5
6
7
8
9
10
11
struct matrix
{
  float elements[16];
  float& operator[](int index) { return elements[index]; }
} m1;

int main()
{
  m1[1] = 2;
  return 0;
}


Assembly looks like:

this is the main function
1
2
3
4
5
6
7
8
9
10
11
12
13
main:
	pushq	%rbp
	movq	%rsp, %rbp
	subq	$32, %rsp
	call	__main
	movl	$1, %edx
	leaq	m1(%rip), %rcx
	call	_ZN6matrixixEi
	movl	$0x40000000, %edx
	movl	%edx, (%rax)
	movl	$0, %eax
	leave
	ret


and here is the assembly for the overloaded operator.
1
2
3
4
5
6
7
8
9
10
11
_ZN6matrixixEi:
	pushq	%rbp
	movq	%rsp, %rbp
	movq	%rcx, 16(%rbp)
	movl	%edx, 24(%rbp)
	movl	24(%rbp), %eax
	cltq
	salq	$2, %rax
	addq	16(%rbp), %rax
	leave
	ret


The version with operator overloading requires a function call, whereas the version with direct access the compiler will simply look up the address of m1.elements and assign directly. Clearly, direct access is faster.

Of course, this is without compiler optimizations, and frankly, the difference in real world applications is pretty much nothing.
Of course, this is without compiler optimizations

And therefore completely irrelevant. No sane person compares performance of the debug/unoptimized builds.

Edit:
Here's the real output, with a modified main function that tricks the compiler into not optimizing the entire loop away:

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
	cMatrix1 m1;
	//cMatrix2 m1; //variant 2

	for (int i=0;i<1000000;i++)
	{
		m1[i%16] = i;
                //m1.elements[i%16] = i; //variant 2
	}
	return m1[15]; 
        //return m1.elements[15]; //variant 2
}


With overloaded operator[]:
1
2
3
4
5
6
7
8
9
10
.L2:
	movl	%eax, -76(%rsp)
	movq	%rax, %rdx
	incl	%eax
	movd	-76(%rsp), %xmm0
	cvtdq2ps	%xmm0, %xmm0
	andl	$15, %edx
	cmpl	$1000000, %eax
	movss	%xmm0, -72(%rsp,%rdx,4)
	jne	.L2



Direct access:
1
2
3
4
5
6
7
8
9
10
.L2:
	movl	%eax, -76(%rsp)
	movq	%rax, %rdx
	incl	%eax
	movd	-76(%rsp), %xmm0
	cvtdq2ps	%xmm0, %xmm0
	andl	$15, %edx
	cmpl	$1000000, %eax
	movss	%xmm0, -72(%rsp,%rdx,4)
	jne	.L2
Last edited on
Great hints Athar, thank You very much ! (i should learn the assembly code check)
Topic archived. No new replies allowed.