不透明参考而不是PImpl。是否可以? [英] Opaque reference instead of PImpl. Is it possible?

查看:164
本文介绍了不透明参考而不是PImpl。是否可以?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


PIMPL Idiom是一种实现隐藏的技术,其中一个公共类包装一个结构或类,这个结构或类在公共类是其一部分的库之外是不可见的。这隐藏了库用户的内部实现细节和数据。


但是可以实现相同的使用

 命名空间Impl {
class FontDelegate;
}

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

protected:
//引用计数
long m_cRef;

// agg字体委托
const Impl :: FontDelegate& m_font;
}

MCanvasFont.cpp

  // helpers 
#includeImplHelpers / FontDelegate.h

MCanvasFont :: MCanvasFont()
:m_cRef ,
m_font(Impl :: FontDelegate())
{
//构造函数体
}

PS

解决方案

程序中有一个错误,它在构造函数的初始化列表中:

  MCanvasFont :: MCanvasFont()
:m_cRef(1),
m_font(Impl :: FontDelegate ())//< --- BANG
{

c $ c> Impl :: FontDelegate()是它构造一个临时对象。这将不会超过构造函数 - 事实上,它实际上在进入构造函数体之前被销毁,因为它的生命周期是它出现的表达式。因此,您的 m_font 引用将立即无效。



手动分配的对象( * new Impl :: FontDelegate())如果分配失败,您处于未定义的区域,除非您的运行时启用了异常。你仍然需要 delete 你的析构函数中的对象。所以参考真的不买你任何优势,它只是使一些不自然的代码。我建议使用一个const指针:

  const Impl :: FontDelegate * const m_font; 

EDIT:只是为了说明问题, / p>

  #include< iostream> 

struct B
{
B(){std :: cout< B constructed \\\
; }
〜B(){std :: cout<< B destroyed\\\
; }
};

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

int main()
{
A a;
a.Foo();
}

如果运行此命令,输出将是:



<$ c $ p> B构造
B销毁
构造
A :: Foo()
销毁

所以 b 几乎立即无效。 >

The PIMPL Idiom is a technique for implementation hiding in which a public class wraps a structure or class that cannot be seen outside the library the public class is part of. This hides internal implementation details and data from the user of the library.

But is it possible to implement the same making use of reference?

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;
}

MCanvasFont.cpp

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

MCanvasFont::MCanvasFont()
: m_cRef(1),
  m_font(Impl::FontDelegate() )
{
    // constructor's body
}

P.S. This code compiles without any problems with G++.

解决方案

There is an error in your program, and it's in the constructor's initialiser list:

MCanvasFont::MCanvasFont()
: m_cRef(1),
  m_font(Impl::FontDelegate() ) // <--- BANG
{

The problem with Impl::FontDelegate() is that it constructs a temporary object. This won't outlive the constructor - in fact it's actually destroyed before entering the constructor body, as it's lifetime is that of the expression in which it appears. Thus your m_font reference is instantly invalid.

While you could initialise it using a manually allocated object (*new Impl::FontDelegate()) you're in undefined territory if that allocation fails unless you have exceptions enabled in your runtime. You'll also still have to delete the object in your destructor anyway. So the reference really doesn't buy you any advantages, it just makes for some rather unnatural code. I recommend using a const pointer instead:

const Impl::FontDelegate* const m_font;

EDIT: Just to illustrate the problem, take this equivalent example:

#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();
}

If you run this, the output will be:

B constructed
B destroyed
A constructed
A::Foo()
A destroyed

So b is invalid almost immediately.

这篇关于不透明参考而不是PImpl。是否可以?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆