Jump to content

C++ (premature) optimization

Guest
Go to solution Solved by colonel_mortis,
17 minutes ago, fpo said:

Integer types use 2 bytes of data. Pointers store an address in 1 byte of data (I think) and that's what makes them more efficient.

In a 64 bit application, a pointer takes up 64 bits = 8 bytes (and on 32 bit, it's 4 bytes). The size of an int varies by platform, but is generally 32 bits = 4 bytes.

 

Optimising a couple of bytes is very definitely premature optimisation. However, in this case method 1 will be more efficient.

In terms of memory, method 1 has 4 bytes for x, while method 2 has 8 bytes.

In terms of speed, method 2 involves a pointer dereference, which is a minimum of one extra instruction (and in the event of a cache miss, it will take several cycles).

 

25 minutes ago, fpo said:

I'm working with SFML & want to create many of the same object with the same dimensions so I created a variable elsewhere to make it easier to change the sizes if I need to.

For that use case, it's usually a better idea to use preprocessor macros, which are resolved at compile time and have no runtime overhead

#define CUSTOM_C_DIMENSIONS 10

Then rather than accessing CustomC::x, you would just use CUSTOM_C_DIMENSIONS.

I think I understand pointers but I'm not sure I'm understanding the atm. (been a while. I've been doing a lot of C# recently.)

 

Quick setup:

Globals.h

Spoiler

extern int i;

 

main.cpp

Spoiler

#include "Globals.h"
#include "customC.h"
int i = 0;

int main()
{
 customC cC(); 
}

 

 

My Question now...
Integer types use 2 bytes of data. Pointers store an address in 1 byte of data (I think) and that's what makes them more efficient.

Is method 1 or method 2 more efficient & do they produce the same desired output? Where I want the variable x in CustomC to be equal to the global variable i.

 

Method 1:

 

CustomC.h

Spoiler

class CustomC {


private:

int x;


}

 

CustomC.cpp

Spoiler

#include "CustomC.h"
#Globals.h
CustomC::CustomC() {
  x = i;
}

 

Method 2:

 

CustomC.h

Spoiler

class CustomC {


private:

int* x;


}

 

 

CustomC.cpp

Spoiler

#include "CustomC.h"
#Globals.h
CustomC::CustomC() {
  x = &i;
}

 



I'm working with SFML & want to create many of the same object with the same dimensions so I created a variable elsewhere to make it easier to change the sizes if I need to.

Link to comment
Share on other sites

Link to post
Share on other sites

Int size is usually dependent on your compiler, but in most cases (read, basically every recent x86 computer based compiler) is 4 bytes. Pointer size is generally dependent on your machine, 4 bytes for 32 bit, 8 bytes for 64 bit. This does almost nothing to affect speed.

 

The speed of these two things depends mostly on what you are doing with them. Dereferencing pointers isn't free, allocating heap space for pointers isn't free, direct variables will require copying memory. Which is faster depends mostly on what you are doing with it, but as a general rule if the data you want to access is small (e.g. a single int), a variable will be faster, if the data you want to access is large (e.g. a file buffer), a pointer will be faster.

 

This isn't an absolute rule though, so testing your use case may be warranted.

¯\_(ツ)_/¯

 

 

Desktop:

Intel Core i7-11700K | Noctua NH-D15S chromax.black | ASUS ROG Strix Z590-E Gaming WiFi  | 32 GB G.SKILL TridentZ 3200 MHz | ASUS TUF Gaming RTX 3080 | 1TB Samsung 980 Pro M.2 PCIe 4.0 SSD | 2TB WD Blue M.2 SATA SSD | Seasonic Focus GX-850 Fractal Design Meshify C Windows 10 Pro

 

Laptop:

HP Omen 15 | AMD Ryzen 7 5800H | 16 GB 3200 MHz | Nvidia RTX 3060 | 1 TB WD Black PCIe 3.0 SSD | 512 GB Micron PCIe 3.0 SSD | Windows 11

Link to comment
Share on other sites

Link to post
Share on other sites

17 minutes ago, fpo said:

Integer types use 2 bytes of data. Pointers store an address in 1 byte of data (I think) and that's what makes them more efficient.

In a 64 bit application, a pointer takes up 64 bits = 8 bytes (and on 32 bit, it's 4 bytes). The size of an int varies by platform, but is generally 32 bits = 4 bytes.

 

Optimising a couple of bytes is very definitely premature optimisation. However, in this case method 1 will be more efficient.

In terms of memory, method 1 has 4 bytes for x, while method 2 has 8 bytes.

In terms of speed, method 2 involves a pointer dereference, which is a minimum of one extra instruction (and in the event of a cache miss, it will take several cycles).

 

25 minutes ago, fpo said:

I'm working with SFML & want to create many of the same object with the same dimensions so I created a variable elsewhere to make it easier to change the sizes if I need to.

For that use case, it's usually a better idea to use preprocessor macros, which are resolved at compile time and have no runtime overhead

#define CUSTOM_C_DIMENSIONS 10

Then rather than accessing CustomC::x, you would just use CUSTOM_C_DIMENSIONS.

HTTP/2 203

Link to comment
Share on other sites

Link to post
Share on other sites

7 minutes ago, BobVonBob said:

Int size is usually dependent on your compiler, but in most cases (read, basically every recent x86 computer based compiler) is 4 bytes. Pointer size is generally dependent on your machine, 4 bytes for 32 bit, 8 bytes for 64 bit. This does almost nothing to affect speed. 

  

The speed of these two things depends mostly on what you are doing with them. Dereferencing pointers isn't free, allocating heap space for pointers isn't free, direct variables will require copying memory. Which is faster depends mostly on what you are doing with it, but as a general rule if the data you want to access is small (e.g. a single int), a variable will be faster, if the data you want to access is large (e.g. a file buffer), a pointer will be faster.

 

This isn't an absolute rule though, so testing your use case may be warranted.

I was most concerned with memory usage though it seems my pointers would be less efficient.

I'm not exactly sure what dereferencing pointers means. I'm guessing it's a similar idea to destructors for objects? Somehow clearing the memory or something.

 

9 minutes ago, colonel_mortis said:

In a 64 bit application, a pointer takes up 64 bits = 8 bytes (and on 32 bit, it's 4 bytes). The size of an int varies by platform, but is generally 32 bits = 4 bytes.

 

Optimising a couple of bytes is very definitely premature optimisation. However, in this case method 1 will be more efficient.

In terms of memory, method 1 has 4 bytes for x, while method 2 has 8 bytes.

In terms of speed, method 2 involves a pointer dereference, which is a minimum of one extra instruction (and in the event of a cache miss, it will take several cycles).

 

For that use case, it's usually a better idea to use preprocessor macros, which are resolved at compile time and have no runtime overhead


#define CUSTOM_C_DIMENSIONS 10

Then rather than accessing CustomC::x, you would just use CUSTOM_C_DIMENSIONS.

I think I'll use the #define. I completely forgot about that. Before I started writing in C# I was thinking so much about how I didn't have defines & had to make enumerations to hack my own defines.

 

Since both of you think small variables shouldn't be declared via pointer I'll avoid them in this case.

Thanks for the help!

Link to comment
Share on other sites

Link to post
Share on other sites

4 minutes ago, fpo said:

I'm not exactly sure what dereferencing pointers means.

Dereferencing a pointer is when you use the data location the pointer is pointing to

int* i;
*i = 5;  //dereference

 

¯\_(ツ)_/¯

 

 

Desktop:

Intel Core i7-11700K | Noctua NH-D15S chromax.black | ASUS ROG Strix Z590-E Gaming WiFi  | 32 GB G.SKILL TridentZ 3200 MHz | ASUS TUF Gaming RTX 3080 | 1TB Samsung 980 Pro M.2 PCIe 4.0 SSD | 2TB WD Blue M.2 SATA SSD | Seasonic Focus GX-850 Fractal Design Meshify C Windows 10 Pro

 

Laptop:

HP Omen 15 | AMD Ryzen 7 5800H | 16 GB 3200 MHz | Nvidia RTX 3060 | 1 TB WD Black PCIe 3.0 SSD | 512 GB Micron PCIe 3.0 SSD | Windows 11

Link to comment
Share on other sites

Link to post
Share on other sites

I wont go over your specific questions as @colonel_mortis alread handled that but i will give you some general advice.

 

For the most part i think premature optimization should not be done. Focus on code cleanliness then optimize when you are running into performance problems after examining your code with a profiler. 

 

However there are some optimizations that you can do right off the bat that do not harm code readability.  For instance passing non atomic data types like structs or classes by reference can be huge savings with very little work on your part (or no extra work). You save your self multiple expensive asm instructions by passing data by reference because you don't need copies or initializations of complex data types. Instead its passing a pointer to the data which is an integer so its an almost free operation.

 

That also ties into principles like RAII which when properly used makes development much smoother.

 

So not all pre optimizations are bad but it comes down to most of them are because you have no idea what actually needs to be optimized.

 

Edit:

Even with my above optimization there are still factors that affect that such as hardware. So always profile your code if you are unsure.

CPU: Intel i7 - 5820k @ 4.5GHz, Cooler: Corsair H80i, Motherboard: MSI X99S Gaming 7, RAM: Corsair Vengeance LPX 32GB DDR4 2666MHz CL16,

GPU: ASUS GTX 980 Strix, Case: Corsair 900D, PSU: Corsair AX860i 860W, Keyboard: Logitech G19, Mouse: Corsair M95, Storage: Intel 730 Series 480GB SSD, WD 1.5TB Black

Display: BenQ XL2730Z 2560x1440 144Hz

Link to comment
Share on other sites

Link to post
Share on other sites

 

24 minutes ago, trag1c said:

For the most part i think premature optimization should not be done.

Yeah, I know. I would have called it optimization if I didn’t think it was too early to optimize. 

24 minutes ago, trag1c said:

RAII

I’ll google that. 

 

Link to comment
Share on other sites

Link to post
Share on other sites

15 hours ago, fpo said:

<snip>

They're functionally different. The first one stores a copy of the value in 'i' to private integer variable 'x'. Each instance of 'CustomC' will have it's own independent 'x' variable. The second example stores a pointer to 'i' to private integer pointer 'x'. All instances of 'CustomC' will have their 'x' point to the same 'i'. If the value of 'i' changes, all instances of 'CustomC' see the change, which is in nearly all cases definitely not what you want. It defeats the purpose of OOP.

 

In fact, you should not be using global variables to begin with, 'i' should not exist.

 

The proper way is to have each instance have it's own 'x', and initialize trough the constructor:

class CustomC
{
public:

	CustomC(int x) : m_x(x) {}

private:

	int m_x;
}

You should not worry about performance for native types. Copying is cheap and native types are small, don't go writing broken code to save a 4 byte copy.

 

If you're really *really* sure you want 'x' to be shared among all instances of 'CustomC', and accept all the dangers that come with it then you can make it static:

#include <iostream>

class CustomC
{
public:

	void PrintX() const { std::cout << m_x << '\n'; }

	static void SetX(int x) { m_x = x; }

private:

	static int m_x;
};

//ODR & init
int CustomC::m_x = 0;

int 
main()
{
	CustomC Instance1;
	CustomC Instance2;

	Instance1.PrintX();
	Instance1.SetX(1337);
	Instance2.PrintX();

	return 0;
}

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×