不透明的参考而不是PImpl.可能吗?

ezp*_*sso 2 c++ design-patterns idioms

PIMPL Idiom是一种实现隐藏的技术,其中公共类包装公共类所属的库外部无法看到的结构或类.这会隐藏来自库用户的内部实现细节和数据.

但是可以实现相同的参考使用吗?

MCanvasFont.h

namespace Impl {
    class FontDelegate;
}

class MCanvasFont
{
public:
    MCanvasFont();
    virtual ~MCanvasFont();

protected:
    // Reference count
    long m_cRef;

    // agg font delegate
    const Impl::FontDelegate& m_font;
}
Run Code Online (Sandbox Code Playgroud)

MCanvasFont.cpp

// helpers
#include "ImplHelpers/FontDelegate.h"

MCanvasFont::MCanvasFont()
: m_cRef(1),
  m_font(Impl::FontDelegate() )
{
    // constructor's body
}
Run Code Online (Sandbox Code Playgroud)

PS此代码编译时没有任何G ++问题.

pmd*_*mdj 5

程序中存在错误,它位于构造函数的初始化列表中:

MCanvasFont::MCanvasFont()
: m_cRef(1),
  m_font(Impl::FontDelegate() ) // <--- BANG
{
Run Code Online (Sandbox Code Playgroud)

问题Impl::FontDelegate()在于它构造了一个临时对象.这不会比构造函数更长 - 实际上它在进入构造函数体之前实际上已被销毁,因为它的生命周期是它出现的表达式的生命周期.因此,您的m_font参考立即无效.

虽然您可以使用手动分配的对象(*new Impl::FontDelegate())初始化它,但如果分配失败,您将处于未定义的区域,除非您在运行时启用了异常.delete无论如何,你仍然需要在你的析构函数中使用该对象.所以这个引用确实没有给你带来任何好处,它只是为了一些相当不自然的代码.我建议使用const指针代替:

const Impl::FontDelegate* const m_font;
Run Code Online (Sandbox Code Playgroud)

编辑:只是为了说明问题,采取这个等效的例子:

#include <iostream>

struct B
{
    B() { std::cout << "B constructed\n"; }
    ~B() { std::cout << "B destroyed\n"; }
};

struct A
{
    const B& b;
    A() :
        b(B())
    {
        std::cout << "A constructed\n";
    }
    void Foo()
    {
        std::cout << "A::Foo()\n";
    }
    ~A()
    {
        std::cout << "A destroyed\n";
    }
};

int main()
{
    A a;
    a.Foo();
}
Run Code Online (Sandbox Code Playgroud)

如果你运行它,输出将是:

B constructed
B destroyed
A constructed
A::Foo()
A destroyed
Run Code Online (Sandbox Code Playgroud)

因此b几乎立即无效.