I have a non-pointer class member that I need to initialize in the constructor:
class Alerter {
protected:
Timer timer;
public:
Alerter(int interval);
};
and then
Alerter::Alerter(int interval) {
timer = createTimer(interval);
}
(simplified code just to demonstrate the problem).
I have some doubts and concerns that timer
probably is first created using its parameter-less constructor and later that instance is overwritten by the contents that the createTimer
function returns.
How good is the approach? The possible answers could be:
Which of these assumptions (or maybe something else) is the most correct?
No, because the object would be infinitely large (because every Node has as members two other Node objects, which each have as members two other Node objects, which each... well, you get the point). Save this answer.
Non-pointers are objects that, well, hold the actual type. int i; is a single integer. char name is a single character and so on. Pointers are objects that contains addresses to other objects.
Pointers are used for file handling. Pointers are used to allocate memory dynamically. In C++, a pointer declared to a base class could access the object of a derived class. However, a pointer to a derived class cannot access the object of a base class.
timer
is first default-constructed and then assigned. Of course you can make assumption about how cheap a Timer
is to default-construct or about compiler optimization, but here you don't need this since can prevent default-construction by using an initializer list:
Alerter::Alerter(int interval) : timer(createTimer(interval)) { }
This will work, unless your Timer
class is copy-assignable but not copy-constructible, which would be weird.
Both constructor will be called (and then the assignment as well).
I have extended your example:
class Timer
{
public:
Timer() : m_interval(0)
{
std::cout << "Constructor withOUT parameter has been called." << std::endl;
}
Timer(int interval) : m_interval(interval)
{
std::cout << "Constructor with parameter has been called." << std::endl;
}
Timer(const Timer& timer)
{
std::cout << "Copy constructor has been called." << std::endl;
m_interval = timer.m_interval;
}
Timer(Timer&& timer)
{
std::cout << "Move constructor has been called." << std::endl;
m_interval = timer.m_interval;
}
void operator=(Timer&& timer)
{
std::cout << "Move assignment has been called." << std::endl;
m_interval = timer.m_interval;
}
private:
int m_interval;
};
class Alerter
{
protected:
Timer timer;
public:
Alerter(int interval)
{
timer = Timer(interval);
}
};
...
Alerter alerter(12);
...
Output:
Constructor withOUT parameter has been called.
Constructor with parameter has been called.
Move assignment has been called.
And answering your question. It is better if the member variables are initialized only once but this is not a hard rule. For example, if the Timer is a very complex object but the default constructor creates just a dummy object, it is not too expensive and acceptable.
So, if you can avoid, better to avoid. Using pointer is a possible solution, but note the followings:
std::unique_ptr
to avoid memory leaks.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With