I have a C++ class which gets instantiated a very large number of times. It has an unsigned short private member. I am getting very different runtime performance depending on whether I initialize it with a hard-coded value 65535 vs when I initialize it with std::numeric_limits<unsigned short>::max(), even though they are ostensibly the same value.
I am trying to understand why there is such a large performance difference, as I would have thought these would be equivalent after compilation. Is it just bad practice to initialize using std::numeric_limits?
Minimal working example below (I've included no initialization for reference):
main.cpp
#include <ostream>
#include <iostream>
#include <ctime>
#include <vector>
#include <limits>
#define TYPE unsigned short
const TYPE max = 65535; // value returned by std::numeric_limits<unsigned short>::max();
class numeric_test_no_init
{
public:
numeric_test_no_init() noexcept
{
return;
}
private:
TYPE _l;
};
class numeric_test_zero_init
{
public:
numeric_test_zero_init() noexcept
{
_l=max;
}
private:
TYPE _l;
};
class numeric_test_max_init
{
public:
numeric_test_max_init() noexcept
{
_l=std::numeric_limits<TYPE>::max();
}
private:
TYPE _l;
};
int main() {
size_t inner_size = 10000000;
size_t outer_size = 1000;
clock_t begin, end;
double elapsed_secs;
begin = clock();
for (size_t i=0;i<outer_size;++i)
std::vector<numeric_test_no_init> no_init(inner_size);
end = clock();
elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
std::cout << "numeric_test_no_init took " << elapsed_secs << " seconds." << std::endl;
begin = clock();
for (size_t i=0;i<outer_size;++i)
std::vector<numeric_test_zero_init> zero_init(inner_size);
end = clock();
elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
std::cout << "numeric_test_zero_init took " << elapsed_secs << " seconds." << std::endl;
begin = clock();
for (size_t i=0;i<outer_size;++i)
std::vector<numeric_test_max_init> max_init(inner_size);
end = clock();
elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
std::cout << "numeric_test_max_init took " << elapsed_secs << " seconds." << std::endl;
return 0;
}
Output:
numeric_test_no_init took 0.003331 seconds.
numeric_test_zero_init took 2.12012 seconds.
numeric_test_max_init took 16.6588 seconds.
I am compiling using GCC 11.4.0 (default for Ubuntu 22.04) with optimization enabled -03.
Update: the performance discrepancy goes away when I upgrade GCC to 13.2. Thank you @retired-ninja for the link demonstrating that.