【问题标题】:Template instantiations and pimpl idiom with unique_ptr带有 unique_ptr 的模板实例化和 pimpl 成语
【发布时间】:2017-09-09 00:36:47
【问题描述】:

我读了 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&lt;Impl&gt; 的声明,然后在这一点上。它将用Impl 实例化模板unique_ptr。并且该实例化代码将包含对Impl 的析构函数的调用。由于此时我们的代码包含对不完整类的析构函数的调用,那么上面的代码如何安全?

【问题讨论】:

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


    【解决方案1】:

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

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

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

    它们都需要Impl的完整定义。

    如果您显式声明这些函数并在Impl 的完整定义可用的地方定义它们,您就可以了。

    更新

    它会看到嵌套类Impl 的声明,然后它会看到unique_ptr&lt;Impl&gt; 的声明,然后在那个时候。它将用Impl 实例化模板unique_ptr

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

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

    不正确。编译器仅在需要时才会生成代码(或实例化)std::unique_ptr&lt;Impl&gt; 的析构函数。那个地方是Something的析构函数。

    Something 的析构函数需要std::unique_ptr&lt;Impl&gt; 的析构函数。
    std::unique_ptr&lt;Impl&gt;的析构函数需要Impl的完整定义。

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

    附言

    更多关于模板实例化的信息可以在Template instantiation details of GCC and MS compilers找到。

    【讨论】:

    • 哪个类的成员函数?我也看到了第一个问题的公认答案,但仍然不明白,完整的unique_ptr 类将在代码中使用给定类型实例化(指向 impl 的指针的声明),并且该实例化将是调用 Impl 的析构函数的代码,但这还不可见。那么代码是如何编译的呢?
    • @Curious,在链接的答案中,Pshared_ptrunique_ptr。在您的情况下,隐式生成的复制构造函数将调用 unique_ptr&lt;Impl&gt; 的复制构造函数。将该逻辑扩展到您的类的其他编译器生成的成员函数。
    • 我认为我没有正确传达我的想法,我会尝试在问题中澄清
    • 发表澄清!
    • @Curious,我没有查阅标准,而是从对该问题的公认答案:编译器是否实际实现两阶段查找不是由标准规定的。然而,为了保持一致,它应该像它一样工作
    【解决方案2】:

    如果你写尝试编译上面的代码并创建一个Something的对象,它会给出一个错误信息:

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

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

    【讨论】:

      猜你喜欢
      • 2014-08-30
      • 1970-01-01
      • 1970-01-01
      • 2010-10-04
      • 1970-01-01
      • 1970-01-01
      • 2013-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多