悬挂指针与显式转换

时间:2015-07-18 04:40:58

标签: c++ raii

在Scott Meyrses Effective C ++中,他提供了一些错误使用隐式转换以及RAII类的例子:

class Font { // RAII class
public:
    explicit Font(FontHandle fh) // acquire resource;
        : f(fh) // use pass-by-value, because the
    {} // C API does
    ~Font() { releaseFont(f ); } // release resource
    ... // handle copying (see Item14)
private:
    FontHandle f; // the raw font resource
};

隐式转换函数:

class Font {
public:
    ...
    operator FontHandle() const // implicit conversion function
    { return f; }
    ...
};

他还提供了这种不良用法的一个例子:

Font f1(getFont());
...
FontHandle f2 = f1; // oops! meant to copy a Font
                    // object, but instead implicitly
                    // converted f1 into its underlying
                    // FontHandle, then copied that

以下是他所说的:

  

现在程序有一个由Font对象f1管理的FontHandle,   但FontHandle也可直接用作f2。那是   几乎从不好。例如,当f1被销毁时,字体将是   发布,和f2将悬挂

为什么f2会悬挂?将FontHandle中包含的f1资源复制到f2后,f2f1将成为完全独立的对象。那么,如果我们发布f1,它将如何影响f2?我们应用 复制 ,而不是 移动

3 个答案:

答案 0 :(得分:2)

FontHandle最终是一个指针本身。 f2是RAII类范围之外的指针的副本。当f1超出范围时,它将释放f1中fonthandle指向的内存...但f2仍然指向它。

“FontHandle”这个名字对象的使用是为了清晰起见,但是很多时候这些C API,分离出来并隐藏实现,会让API函数看起来像void指针(void *)那样只有API具有取消引用和使用的信息。然后他们可能会执行类似typedef void *FontHandle的操作,以便您知道void指针在语义上代表什么。

答案 1 :(得分:1)

假设FontHandle是一个指针,那么f2和私有成员f1.f将指向同一个东西。如果f1不再存在(例如,超出范围,或明确释放),那么f2将是一个悬空指针。

答案 2 :(得分:0)

请注意转换功能:

operator FontHandle() const // implicit conversion function
{ return f; }

每当您需要将Font转换为FontHandle时,只需返回获取的句柄即可。 F2将是这个对象本身,而不是副本。 C ++希望你自己在这里制作一个副本。此外,

当你这样做时

FontHandle f2 = f1; // oops! meant to copy a Font

这会调用上面的运算符。它不会调用复制构造函数。为什么?

声明t1 = t2;等同于:

t1.operator=(t2);

由于您尚未定义上述隐式转化,如上所述。只有在执行

时才会调用复制构造函数
Font f2 = f1;