Reputation: 35982
I have defined a member variable as follows. Since the variable will not be passed around, so I decide to use scoped_ptr rather than shared_ptr here.
class ClassName
{
public:
ClassName()
{
Initialize();
}
virtual void Initialize() = 0;
protected:
boost::scoped_ptr<int> m_scpInt;
}
class ClassNameB : public ClassName
{
public:
virtual void Initialize()
{
m_scpInt.reset(new int(100));
}
}
Due to the limit of the scoped_ptr, if I decide to defer the initialization of the variable in a later time, the only option I get is to call reset.
Q1> Is this a good practice?
Q2> Otherwise, is there a better solution?
Thank you
/// Updated -1 ///
This is what I really want to do.
I want to enforce that each of the derived class define a function called Initialize and which in turn calls function InitializeVarA and InitializeVarB. As you indicate, that we cannot call virtual function in the constructor.
class ClassName
{
public:
ClassName()
{
}
virtual void Initialize()
{
InitializeVarA();
InitializeVarB();
}
protected:
virtual void InitializeVarA() {}
virtual void InitializeVarB() {}
}
class ClassNameB : public ClassName
{
public:
ClassNameB()
{
}
virtual void Initialize()
{
InitializeVarA();
InitializeVarB();
}
protected:
virtual void InitializeVarA() {}
virtual void InitializeVarB() {}
}
ClassNameB cb;
cb.Initialize();
Do I have a better solution than this?
Upvotes: 1
Views: 723
Reputation: 254431
Is this a good practice?
Using reset
to reset a scoped pointer is fine.
Trying to initialise a derived class by calling a virtual function from the base class's constructor is not just bad practice; it's wrong. At that point, the dynamic type of the object is the base class, and the function is pure virtual, so calling it gives undefined behaviour.
Even if you made it non-pure, you still can't call the derived class's override at that point, so the pointer won't be reset.
Otherwise, is there a better solution?
You could do it in the derived class's constructor, which is invoked immediately after the base class's:
class Base {
public:
Base() { /* don't call any virtual functions here */ }
protected:
boost::scoped_ptr<int> p;
};
class Derived : public Base {
public:
Derived() {
p.reset(new int(100));
}
};
Or you could pass the allocated memory to the base class constructor and initialise the pointer from that. That's slightly dangerous though - you must make sure you initialise the pointer immediately, before anything that might throw an exception, or the memory might leak.
class Base {
public:
Base(int * p) : p(p) {}
private: // doesn't need to be protected now
// (unless something else in the derived class needs access)
boost::scoped_ptr<int> p;
};
class Derived : public Base {
public:
Derived() : Base(new int(100)) {}
};
In C++11, you could use unique_ptr
, which is movable, to avoid that risk of a leak:
class Base {
public:
typedef std::unique_ptr<int> ptr;
Base(ptr && p) : p(p) {}
private:
ptr p;
};
class Derived : public Base {
public:
Derived() : Base(ptr(new int(100))) {}
};
Upvotes: 4