在PIMPL习语中使用引用的利弊
Pros and Cons of usage of reference in case of PIMPL idiom
如前所述,对于PIMPL习语,您可以使用引用(d-reference)而不是指针(d-pointer)。
我想知道这个实现是否有什么严重的问题,利弊是什么。
优点:
- 更短的语法,因为使用"."代替"->"。
- …
缺点:
- 如果new objectprivate ()失败且new不抛出(例如:new(std::nothrow)或custom new)并返回nullptr怎么办?你需要实现额外的东西来检查引用是否有效。如果是指针,你只需使用:
if (m_Private)
m_Private->Foo();
之前- 在对象具有复杂初始化逻辑的多个构造函数的罕见情况下,解决方案可能不适用。[©JamesKanze]
- 使用指针进行内存管理更自然。[©JamesKanze]
- 需要考虑一些额外的实现细节(使用swap())来确保异常安全(例如赋值操作符的实现)[©Matt Yang]
- …
下面是示例代码:
// 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();
}
这只是风格的问题。我倾向于不使用类中的引用作为开始,所以在编译防火墙看起来更自然。但是有通常没有真正的优势,但new
可以只有会因异常而失败。
可以使用指针的一种情况是对象有许多不同的构造函数,其中一些需要在调用new
之前进行初步计算。在这个在这种情况下,您可以使用NULL
初始化指针,然后调用一个通用的初始化例程。我认为这种情况很少见,然而。(我记得我遇到过一次。)
只是另一个风格考虑:很多人不喜欢像delete &something;
这样的东西,如果你使用引用而不是指针,这是需要的。同样,对象管理内存使用指针似乎更自然(至少对我来说)。
我认为编写异常安全代码不方便。
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));
}
一些快速和明显的添加:
Pro
- 引用不能是
0
。 - 该引用不能被分配给另一个实例。
- 类的职责/实现更简单,因为变量更少。 编译器可以做一些优化。
的
- 该引用不能被分配给另一个实例。 在某些情况下,参考将过于严格。
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 如何在c++中使用引用实现类似python的行为
- 编译C++时未定义的引用
- Ctypes wstring通过引用传递
- c++r值引用应用于函数指针
- 理解c++中的引用
- C++取消引用指针.为什么会发生变化
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 强制转换为引用类型
- 引用一个已擦除类型(void*)的指针
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 具有默认值的引用获取函数
- 如何使用基类指针引用派生类成员
- 不透明引用而不是 PImpl.可能吗
- 在PIMPL习语中使用引用的利弊