Reputation: 946
If I have two different constant members variables, which both need to be initialized based on the same function call, is there a way to do this without calling the function twice?
For example, a fraction class where numerator and denominator are constant.
int gcd(int a, int b); // Greatest Common Divisor
class Fraction {
public:
// Lets say we want to initialize to a reduced fraction
Fraction(int a, int b) : numerator(a/gcd(a,b)), denominator(b/gcd(a,b))
{
}
private:
const int numerator, denominator;
};
This results in wasted time, as the GCD function is called twice. You could also define a new class member, gcd_a_b
, and first assign the output of gcd to that in the initializer list, but then this would lead to wasted memory.
In general, is there a way to do this without wasted function calls or memory? Can you perhaps create temporary variables in an initializer list?
Upvotes: 54
Views: 3649
Reputation: 63775
In general, is there a way to do this without wasted function calls or memory?
Yes. This can be done with a delegating constructor, introduced in C++11.
A delegating constructor is a very efficient way to acquire temporary values needed for construction before any member variables are initialized.
int gcd(int a, int b); // Greatest Common Divisor
class Fraction {
public:
// Call gcd ONCE, and forward the result to another constructor.
Fraction(int a, int b) : Fraction(a,b,gcd(a,b))
{
}
private:
// This constructor is private, as it is an
// implementation detail and not part of the public interface.
Fraction(int a, int b, int g_c_d) : numerator(a/g_c_d), denominator(b/g_c_d)
{
}
const int numerator, denominator;
};
Upvotes: 73
Reputation: 7100
The member vars are initialized by the order they are declared in the class declaration, hence you can do the following (mathematically)
#include <iostream>
int gcd(int a, int b){return 2;}; // Greatest Common Divisor of (4, 6) just to test
class Fraction {
public:
// Lets say we want to initialize to a reduced fraction
Fraction(int a, int b) : numerator{a/gcd(a,b)}, denominator(b/(a/numerator))
{
}
//private:
const int numerator, denominator;//make sure that they are in this order
};
//Test
int main(){
Fraction f{4,6};
std::cout << f.numerator << " / " << f.denominator;
}
No need for calling another constructors or even making them.
Upvotes: 10
Reputation: 839
@Drew Dormann gave a solution similar to what I had in mind. Since OP never mentions not being able to modify the ctor, this can be called with Fraction f {a, b, gcd(a, b)}
:
Fraction(int a, int b, int tmp): numerator {a/tmp}, denominator {b/tmp}
{
}
Only this way there is no second call to a function, constructor or otherwise, so it's no wasted time. And it's no wasted memory since a temporary would have to be created anyway, so you may as well make good use of it. It also avoids an extra division.
Upvotes: -3