FAQ 2.21
(1)总的观点:努力避免这种状况,(2)如果无法避免,使用auto_ptr.
尽量避免包含在堆上分配的对象的指针.例如,分析一下一个car类包含一个engine的情行。这儿有两个选择:教好的方式是engined对象直接嵌入到car对象内,不好的方式是car对象包含一个指向engine对象的指针,car从堆分配engine对象,下面是例子:
#include <iostream> using namespace std; class Engine { public: Engine(); virtual void start(); }; Engine::Engine() { cout << "Engine constructor/n"; } void Engine::start() { cout << "Engine::start()/n"; }
car类的代码在下面,Car类,用更好的方法:每个Car对象直接包含它的Engine对象.与用在堆上分配的指向Engine对象
的指针相比较,类car展示的技术更容易,更快,更安全,并且使用更少的内存。
class Car { public: Car(); virtual void startEngine(); protected: Engine e_; <-- 1 }; Car::Car() : e_ () <-- 2 { // Intentionally left blank } void Car::startEngine() { e_.start(); <-- 3 }
(1) 每一个Engin嵌入到一个Car对象中(2) 初始化Car对象中的Engine对象(3) 调用Engin对象的start()成员函数
尽管这是很好的方法,有时候也不是必要的,从堆上分配内部对象并且有一个外部对象包含一个指向内部对象的指针,这时候就需要使用auto_ptr:
#include <memory> <-- 1 using namespace std; typedef auto_ptr<Engine> EnginePtr; class Car { public: Car(); virtual void startEngine(); virtual ~Car(); Car(const Car& c); <-- 2 Car& operator= (const Car& c); <-- 3 protected: EnginePtr p_; <-- 4 }; Car::Car() : p_ (new Engine()) <-- 5 { // Intentionally left blank } void Car::startEngine() { p_->start(); <-- 6 }
(1) 得到 auto_ptr
(2) 拷贝构造函数
(3) 重载操作符
(4) 每个Car对象包含一个auto_ptr指针
(5) 为每个Car对象分配一个Engine对象
(6) 为Engine对象调用start()成员函数
逻辑上第二个例子仍然是一个包含或者has-a的关系,但是实际上还是有些不同.注意三个扩展成员函数必须在Car
类的第二个版本中声明.需要扩展成员函数是因为auto_ptr被用来控制car的Engine对象。
最重要的信息是这比使用原始的指针危险性更小,就象Car *。因此下面的技术不应当被使用。
class Car { public: Car(); virtual void startEngine(); virtual ~Car(); Car(const Car& c); <-- 1 Car& operator= (const Car& c); <-- 2 protected: Engine* p_; <-- 3
(1) 拷贝构造函数(2) 重载操作符
(3) 尽量避免原始指针分配对象。