Reputation: 30028
recently I was looking at old horrible mess of a class...
Long story short it would help with thread safety if one member was const.
But the problem is that member is initialized in ctor, and it is nontrivial construction. So I was thinking about creating a special init function for that member. Is that a good decision.
Small super simple example(real code is full of conditionals :) and try-s)
:
class ComplexInitList
{
std::pair<double,double> init_pair(const int first, const int second)
{
if ((first == 0) || (second == 0))
throw std::invalid_argument("div by 0");
return std::make_pair(1.0/first, 1.0/second);
}
const std::pair<double,double> p;
public:
ComplexInitList(int a, int b):p(init_pair(a,b))
{
std::cout << p.first << ", " << p.second << std::endl;
}
};
Upvotes: 4
Views: 228
Reputation: 1347
Late to the party, but to add for any new search-engine'ers:
If init_pair
isn't going to be used anywhere else I find a lambda to be the most elegant way of solving this problem:
class ComplexInitList
{
const std::pair<double,double> p;
public:
ComplexInitList(const int a, const int b) :
p([](const int a, const int b) {
if ((first == 0) || (second == 0)) {
throw std::invalid_argument("div by 0");
}
return std::make_pair(1.0/first, 1.0/second);
}()) // <-- Note the extra '()' with immediately calls the lambda!
{
std::cout << p.first << ", " << p.second << std::endl;
}
};
Upvotes: 2
Reputation: 45410
To initialize a const data member the only way is to initialize it in member initializer list
.
p
is a const, so it can be initialized to a value, but it can't be assigned a value. Conceptually, calling a constructor creates an object before the code
within the brackets is executed. Thus calling ComplexInitList(int a, int b):p(init_pair(a,b))
cause the program first to allocate space for member p
.
Then program flow enters
the brackets and uses ordinary assignment to place values into the allocated space. So if you want to initialize a const data member, you have to initialize it in member initializer list
Upvotes: 1
Reputation: 171127
This is actually a common and accepted solution to this problem. If possible, consider making the init function static, so that unexpected semantics of operations on object under construction (such as behaviour of virtual calls) can't kick in.
Upvotes: 4