在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
后,f2
和f1
将成为完全独立的对象。那么,如果我们发布f1
,它将如何影响f2
?我们应用 复制 ,而不是 移动 。
答案 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;