如上所述here,PIMPL idiom可以使用引用( d-reference )而不是指针( d-pointer )。
我试图了解此实施是否存在任何严重问题以及利弊是什么。
优点:
缺点:
if (m_Private)
m_Private->Foo();
此处为示例代码示例:
// Header file
class ObjectPrivate;
class Object
{
public:
Object();
virtual ~Object();
virtual void Foo();
private:
ObjectPrivate& m_Private;
};
// Cpp file
class ObjectPrivate
{
public:
void Boo() { std::cout << "boo" << std::endl; }
};
Object::Object() :
m_Private(* new ObjectPrivate())
{
}
Object::~Object()
{
delete &m_Private;
}
void Object::Foo()
{
m_Private.Boo();
}
答案 0 :(得分:6)
这真的只是风格问题。我倾向于不使用
类中的引用开头,所以在中使用指针
编译防火墙似乎更自然。但是有
通常没有真正的优势:new
可以
仅通过异常失败。
你可能喜欢指针的一种情况是
对象有很多不同的构造函数,其中一些需要
在致电new
之前进行初步计算。在这
例如,您可以使用NULL
初始化指针,然后调用
常见的初始化例程。我认为这种情况很少见,
然而。 (我已经遇到过一次,我记得。)
编辑:
只是另一种风格考虑因素:很多人不喜欢像delete &something;
这样的东西,如果你使用引用而不是指针则需要它。再一次,管理内存的对象使用指针似乎更自然(至少对我而言)。
答案 1 :(得分:1)
我认为编写异常安全的代码并不方便。
Object::operator=(Object const&)
的第一个版本可能是:
Object& operator=(Object const& other)
{
ObjectPrivate *p = &m_Private;
m_Private = other.m_Private; // Dangerous sometimes
delete *p;
}
如果ObjectPrivate::operator=(ObjectPrivate const&)
抛出异常,那就太危险了。那么使用临时变量呢?啊哈,没办法。如果您想要更改m_Private,则必须调用operator=()
。
所以,void ObjectPrivate::swap(ObjectPrivate&) noexcept
可以充当我们的救世主。
Object& operator=(Object const& other)
{
ObjectPrivate *tmp = new ObjectPrivate(other.m_Private);
m_Private.swap(*tmp); // Well, no exception.
delete tmp;
}
然后考虑void ObjectPrivate::swap(ObjectPrivate&) noexcept
的实施。我们假设ObjectPrivate可能包含没有swap() noexcept
或operator=() noexcept
的类实例。我认为这很难。
好吧,这个假设太严格了,有时也不正确。即便如此,在大多数情况下,ObjectPrivate也没有必要提供swap() noexcept
,因为它通常是一个集中数据的辅助结构。
相比之下,指针可以节省大量的脑细胞。
Object& operator=(Object const& other)
{
ObjectPrivate *tmp = new ObjectPrivate(*other.p_Private);
delete p_Private;
p_Private = tmp; // noexcept ensured
}
如果使用智能指针,它会更加优雅。
Object& operator=(Object const& other)
{
p_Private.reset(new ObjectPrivate(*other.p_Private));
}
答案 2 :(得分:1)
一些快速而明显的补充:
<强>临强>
0
。<强> N 强>