使用unique_ptr进行模板实例化和pimpl习语

时间:2017-04-13 03:15:08

标签: c++ c++11 c++14 unique-ptr pimpl-idiom

我读过Howard Hinnant(Is std::unique_ptr<T> required to know the full definition of T?)的答案,然后这个答案(How is a template instantiated?)我正在思考。如果你有这样的课程

class Something {
    Something(); 
    ~Something();
    class Impl;
    std::unique_ptr<Impl> impl;
};

当编译类时,unique_ptr将被实例化(正如我从上面的其他答案中得出的那样)。那么为什么以后没有定义类Impl可以呢?实例化不会要求Impl的析构函数存在吗?

注意以下内容旨在澄清上述问题。

当编译器查看类Something的定义时,我正在思考它的方式。它将看到嵌套类Impl的声明,然后它将看到unique_ptr<Impl>的声明,并在那时。它将使用unique_ptr实例化模板Impl。并且该实例化代码将包含对Impl的析构函数的调用。由于此时我们的代码包含对不完整类的析构函数的调用,上面的代码如何安全?

2 个答案:

答案 0 :(得分:1)

The accepted answer to the first question包含一个用例表,其中需要Impl的完整定义。

在您的情况下,编译器隐式生成以下成员函数:

  • 复制构造函数
  • 移动构造函数
  • 复制分配运算符
  • 移动赋值运算符。

所有这些都需要Impl的完整定义。

如果您明确声明这些功能并将其定义在Impl的完整定义可用的位置,那么您就可以了。

<强>更新

  

它将看到嵌套类Impl的声明,然后它将看到unique_ptr<Impl>的声明,并在那时。它将使用unique_ptr实例化模板Impl

这在某种程度上是正确的。并非unique_ptr的所有成员函数都将在那时实例化。

  

该实例化代码将包含对Impl的析构函数的调用。

不正确。只有在需要时,编译器才会生成std::unique_ptr<Impl>的析构函数(或实例化)。那个地方是Something的析构函数。

Something的析构函数需要std::unique_ptr<Impl>的析构函数 std::unique_ptr<Impl>的析构函数需要Impl的完整定义。

换句话说,Impl的完整定义必须对Something的析构函数可见。

<强> PS

有关模板实例化的更多信息,请访问Template instantiation details of GCC and MS compilers

答案 1 :(得分:0)

如果您尝试编译上述代码并创建Something对象,则会显示错误消息:

Semantic issue:
memory:2523:27: Invalid application of 'sizeof' to an incomplete type 
'Something::Impl'

简而言之,代码是无法编译的,在这种情况下没有必要考虑安全性。